BST与AVL的C++模板实现
2014-04-18 15:29
477 查看
C++实现BSTree与AVLTree
回顾树结构时,本打算写个小程序实现一下练练手。
而作为常见的树结构,BSTree与AVLTree 应该是最容易被提到的。关于这连个树结构,这里不负责讲解。
但是在实现的时候却发现有许多细节上处理需要注意。思想很简单,实现起来还是有一定难度的。像能轻松知道破解原理和步骤,但是实际破解却费时费力。
遵从 算法导论的思想 喜欢在 树节点中增加父节点。所以与其他实现可能有些不同。
本代码实现许多地方用了
一步一步写平衡二叉树 博文中的内容。文章写的蛮清晰,推荐以此为参考
网上有很多的思想介绍和伪码,但是具体能用的倒不多,下面给出自己编写的代码,测试且单步过,完全可用(可花了好几天...)
下面贴出源码
(源码可能有些冗余,如果有改进后更好的方式,可给我反馈一份 :-D )
然后有测试程序:
示例结果:
中序遍历的结果,每行数据为(数值,出现次数,节点高度)
下面这个结果中(4,3,2)为根节点,3表示4加入了3此,2表示4的高度为2
初始树结构为:
回顾树结构时,本打算写个小程序实现一下练练手。
而作为常见的树结构,BSTree与AVLTree 应该是最容易被提到的。关于这连个树结构,这里不负责讲解。
但是在实现的时候却发现有许多细节上处理需要注意。思想很简单,实现起来还是有一定难度的。像能轻松知道破解原理和步骤,但是实际破解却费时费力。
遵从 算法导论的思想 喜欢在 树节点中增加父节点。所以与其他实现可能有些不同。
本代码实现许多地方用了
一步一步写平衡二叉树 博文中的内容。文章写的蛮清晰,推荐以此为参考
网上有很多的思想介绍和伪码,但是具体能用的倒不多,下面给出自己编写的代码,测试且单步过,完全可用(可花了好几天...)
下面贴出源码
(源码可能有些冗余,如果有改进后更好的方式,可给我反馈一份 :-D )
//BST //参考博客:http://www.cppblog.com/cxiaojia/archive/2014/03/02/187776.html #ifndef _BSTREE_H #define _BSTREE_H #include <stdio.h> #define _CRT_RAND_S #include <stdlib.h> #include <iostream> using namespace std; //二叉树节点 template<class T> class TreeNode { public: TreeNode():lson(NULL),rson(NULL),parrent(NULL),freq(1),hg(0){} public: T data; //数据 int freq; //频率,默认=1 int hg; //高度,默认=0 TreeNode* lson; //指向左儿子的地址 TreeNode* rson; //指向右儿子的地址 TreeNode* parrent; //指向父节点的地址 }; //BST树类的属性和方法声明 template<class T> class BSTree { public: TreeNode<T>* root ; //根 public: BSTree(TreeNode<T>* p=NULL){ root = p; } TreeNode<T>* Search(T x); //查找 data == x 的节点 TreeNode<T>* Min(TreeNode<T>* x); //返回最小节点(最左子节点) TreeNode<T>* Max(TreeNode<T>* x); //返回最大节点(最右子节点) TreeNode<T>* Successor(TreeNode<T>* x); //返回节点x的后继 TreeNode<T>* Predecessor(TreeNode<T>* x); //返回x的前趋 TreeNode<T>* Insert(T x); //插入,返回插入点 void Insert2(T x); //递归插入 void InsertPt(TreeNode<T>* &node, T &x); //在node下面插 bool Delete(T x); //删除 void TraverseTree(); //遍历 void InTraverNode(TreeNode<T>* node); //中序遍历节点node }; //AVL树属性和方法声明 template<class T> class AVLTree:public BSTree<T> { //private: // TreeNode<T>* root; //根节点 private: // void insertpri(TreeNode<T>* &node,T x);//插入 // TreeNode<T>* findpri(TreeNode<T>* node,T x);//查找 // void insubtree(TreeNode<T>* node);//中序遍历 // void Deletepri(TreeNode<T>* &node,T x);//删除 int height(TreeNode<T>* node);//求树的高度 void SingRotateLeft(TreeNode<T>* &k2);//左左情况下的旋转 void SingRotateRight(TreeNode<T>* &k2);//右右情况下的旋转 void DoubleRotateLR(TreeNode<T>* &k3);//左右情况下的旋转 void DoubleRotateRL(TreeNode<T>* &k3);//右左情况下的旋转 public: AVLTree(TreeNode<T>* p=NULL):BSTree(p){} void Insert2(T x); //递归插入 void InsertPt(TreeNode<T>* &node, T &x); //在node节点下插入 void Delete(T x); //删除操作 void DeletePt(TreeNode<T>* &node, T &x); //在node节点下删除 TreeNode<T>* Search(T x); //查找接口 void TraverseTree(); //遍历 void InTraverNode(TreeNode<T>* node); //中序遍历节点node }; ///////////////////////////////////////////////////////////// ////////// BST 树实现 //////////// ///////////////////////////////////////////////////////////// //在树中中查找 data为 x 的节点 template<class T> TreeNode<T>* BSTree<T>::Search(T x) { TreeNode<T>* tmp = root; while( tmp && tmp->data != x ) { if( x < tmp->data ) tmp = tmp->lson; else tmp = tmp->rson; } return tmp; } //返回 节点x 为根 最小节点 template<class T> TreeNode<T>* BSTree<T>::Min(TreeNode<T>* x) { TreeNode<T>* tmp = NULL; while(x) { tmp = x; x = tmp->lson; } return tmp; } //返回 节点x 为根 的最大节点 template<class T> TreeNode<T>* BSTree<T>::Max(TreeNode<T>* x) { TreeNode<T>* tmp = NULL; while(x) { tmp = x; x = tmp->rson; } return tmp; } //后继节点,大于 x 关键字的最小节点(取决于树中是否允许相同元素存在) template<class T> TreeNode<T>* BSTree<T>::Successor(TreeNode<T>* x) { if( !x ) return NULL; if ( x->rson ) return Min(x->rson); //退回父节点,从父节点继续查找,必须为 x 的最低祖先节点,且 x 为其左子树 TreeNode<T>* tmp = x->parrent; while( tmp && tmp->lson != x) ///父节点存在,且父节点的左子树 为 x 的祖先 { x = tmp->parrent; tmp = x->parrent; } return tmp; } //前趋节点,小于 x 关键字的最大节点 template<class T> TreeNode<T>* BSTree<T>::Predecessor(TreeNode<T>* x) { if( !x ) return NULL; if ( x->lson) return Max(x); //退回父节点,从父节点查找,必须为 x 的最低祖先,且x为其右子树 TreeNode<T>* tmp = x->parrent; while(tmp && tmp->rson != x ) { x = tmp->parrent; tmp = x->parrent; } return tmp; } template<class T> TreeNode<T>* BSTree<T>::Insert(T x) //直接插入 { TreeNode<T>* tmp = root; TreeNode<T>* pPar = tmp; while( tmp ) { pPar = tmp ; if( x < tmp->data ) tmp = tmp->lson; else if( x > tmp->data) tmp = tmp->rson; else { tmp->freq++; return tmp; } } TreeNode<T>* pNode = new TreeNode<T>; pNode->data = x; pNode->parrent = pPar; if ( !pPar ) root = pNode; else if( x < pPar->data ) pPar->lson = pNode; else pPar->rson = pNode ; return pNode ; } template<class T> //在节点node 下面插入x,递归插入,据此可写出其他操作的递归方式 void BSTree<T>::InsertPt(TreeNode<T>* &node, T&x) { if( !node ) { node = new TreeNode<T>; node->data = x; return; } if( x < node->data ) { if( node->lson ) InsertPt(node->lson, x); else { node->lson = new TreeNode<T>; node->lson->data = x ; node->lson->parrent = node; } } else if( x > node->data) { if( node->rson ) InsertPt(node->rson, x); else { node->rson = new TreeNode<T>; node->rson->data = x ; node->rson->parrent = node; } } else ++(node->freq); } //插入接口2 template<class T> void BSTree<T>::Insert2(T x) { InsertPt(root, x); } //删除节点 template<class T> bool BSTree<T>::Delete(T x) { TreeNode<T>* pret = Search(x); if( !pret ) //未找到 return false; if ( pret->lson && pret->rson) //该节点两个孩子都存在 { //一定存在后继节点 //找到 pret 的后继,并把后继节点的值赋值给 pret ,然后将后继删掉 TreeNode<T>* pSuc = Successor(pret); //step1: 将后继复制过去,覆盖当前节点 pret->data = pSuc->data; pret->freq = pSuc->freq; //step2:删除后继节点,该后继节点肯定没有左儿子; if( pSuc->parrent->lson == pSuc) pSuc->parrent->lson = pSuc->rson; else pSuc->parrent->rson = pSuc->rson; if( pSuc->rson ) pSuc->rson->parrent = pSuc->parrent ; pret = pSuc; } else //此节点有 0 或 1 个儿子 { TreeNode<T>* pPar = pret->parrent; if ( !pPar ) //即pret为根节点 { if 4000 ( pret->lson ) { root = pret->lson; root->parrent= NULL; } else if( pret->rson ) { root = pret->rson; root->parrent = NULL; } else root = NULL; } else { if( pPar->lson == pret ) { if ( pret->lson ) { pPar->lson = pret->lson; pret->lson->parrent = pPar; } else if( pret->rson ) { pPar->lson = pret->rson; pret->rson->parrent = pPar; } else pPar->lson = NULL; } else { if ( pret->lson ) { pPar->rson = pret->lson; pret->lson->parrent = pPar; } else if( pret->rson ) { pPar->rson = pret->rson; pret->rson->parrent = pPar; } else pPar->rson = NULL; } } } delete pret; pret = NULL; return true; } //中序遍历 节点node template<class T> void BSTree<T>::InTraverNode(TreeNode<T>* node) { if ( !node) return; InTraverNode(node->lson); cout<<"("<<node->data<<","<<node->freq<<")"<<endl; InTraverNode(node->rson); } //遍历节点 template<class T> void BSTree<T>::TraverseTree() { InTraverNode(root); } ////////////////////////////////////////////////////////////////////////// ////////// AVL树实现,AVL的核心是旋转算法 ////////////// ////////////////////////////////////////////////////////////////////////// template<class T> int AVLTree<T>::height(TreeNode<T>* node) //返回 node 点的高度 { if( !node )//空节点 return -1; node->hg =( height(node->lson) > height(node->rson) )? height(node->lson)+1 : height(node->rson)+1 ; return node->hg; } //左左情况 template<class T> void AVLTree<T>::SingRotateLeft(TreeNode<T>* &k2) { TreeNode<T>* pPar = k2->parrent; TreeNode<T>* k1= k2->lson; TreeNode<T>* k2tmp = k2; //需要将K2的 值临时保存,因为应用操作在将 k1 赋值给 pPar 的孩子时,k2值也变化了 //step1:把 k1 顶上去 if( pPar) { if( pPar->lson == k2 ) pPar->lson = k1; else pPar->rson = k1; } k1->parrent = pPar; //step2:把 K1 右孩子接到 K2 左孩子处 k2tmp->lson = k1->rson; if( k1->rson) k1->rson->parrent = k2tmp; //step3:把 K2 接到 K1 右孩子处 k1->rson = k2tmp; k2tmp->parrent = k1; //注意此时 K2 的高度 -2 k2tmp->hg =height(k2tmp); k2->hg = height(k2); k2 = k1; } //右右情况 template<class T> void AVLTree<T>::SingRotateRight(TreeNode<T>* &k2) { TreeNode<T>* pPar = k2->parrent; TreeNode<T>* k1= k2->rson; TreeNode<T>* k2tmp = k2; //需要将K2的 值临时保存,因为应用操作在将 k1 赋值给 pPar 的孩子时,k2值也变化了 //step1:把 k1 顶上去 if( pPar) { if( pPar->lson == k2 ) pPar->lson = k1; else pPar->rson = k1; } k1->parrent = pPar; //step2:把 K1 右孩子接到 K2 左孩子处 k2tmp->rson = k1->lson; if( k1->lson) k1->lson->parrent = k2tmp; //step3:把 K2 接到 K1 右孩子处 k1->lson = k2tmp; k2tmp->parrent = k1; //重新计算树高 height(k2tmp); height(k2); k2 = k1 ; } //左右情况 template<class T> void AVLTree<T>::DoubleRotateLR(TreeNode<T>* &k3) { SingRotateRight(k3->lson); SingRotateLeft(k3); } //右左情况 template<class T> void AVLTree<T>::DoubleRotateRL(TreeNode<T>* &k3) { SingRotateLeft(k3->rson); SingRotateRight(k3); } //重写插入 template<class T> void AVLTree<T>::InsertPt(TreeNode<T>* &node, T &x) { if ( !node ) //根节点处 { node = new TreeNode<T>; node->data = x; node->hg = height(node); return; } if( x < node->data ) //左子树操作 { if( node->lson ) InsertPt(node->lson, x); else { node->lson = new TreeNode<T>; node->lson->data = x ; node->lson->parrent = node; node->lson->hg = height(node->lson); } if ( 2 == height(node->lson) - height(node->rson)) { if( x< node->lson->data ) SingRotateLeft(node); else DoubleRotateLR(node); } //重新 算树高 height(node); } else if ( x > node->data) //右子树操作 { if( node->rson ) InsertPt(node->rson, x); else { node->rson = new TreeNode<T>; node->rson->data = x ; node->rson->parrent = node; node->rson->hg = height(node->rson); } if( 2 == height(node->rson) - height(node->lson) ) { if ( x > node->rson->data) SingRotateRight(node); else DoubleRotateRL(node); } //重新 算树高 height(node); } else ++(node->freq); } //插入接口 template<class T> void AVLTree<T>::Insert2(T x) { InsertPt(root, x); } //中序遍历 节点node template<class T> void AVLTree<T>::InTraverNode(TreeNode<T>* node) { if ( !node) return; InTraverNode(node->lson); cout<<"("<<node->data<<","<<node->freq<<","<<node->hg<<")"<<endl; InTraverNode(node->rson); } //遍历节点 template<class T> void AVLTree<T>::TraverseTree() { InTraverNode(root); } //查找接口 template<class T> TreeNode<T>* AVLTree<T>::Search(T x) { return BSTree<T>::Search(x); } template<class T> void AVLTree<T>::DeletePt(TreeNode<T>* &node, T &x) { if(node==NULL) return ;//没有找到值是x的节点 if(x < node->data) { DeletePt(node->lson, x);//如果x小于节点的值,就继续在节点的左子树中删除x if( 2 == height(node->rson) - height(node->lson) ) { if( node->rson->lson && (height(node->rson->lson)>height(node->rson->rson)) ) DoubleRotateRL(node); else SingRotateRight(node); } } else if(x > node->data) { DeletePt(node->rson, x);//如果x大于节点的值,就继续在节点的右子树中删除x if( 2== height(node->lson) - height(node->rson) ) { if( node->lson->rson && ( height(node->lson->rson) > height(node->lson->lson) )) DoubleRotateLR(node); else SingRotateLeft(node); } } else//如果相等,此节点就是要删除的节点 { if( node->lson && node->rson )//此节点有两个儿子 { TreeNode<T>* temp = node->rson;//temp指向节点的右儿子 while(temp->lson!=NULL) temp=temp->lson;//找到右子树中值最小的节点 //把右子树中最小节点的值赋值给本节点 node->data=temp->data; node->freq=temp->freq; DeletePt(node->rson, temp->data); //删除右子树中最小值的节点 if( 2== height(node->lson) - height(node->rson) ) { if(node->lson->rson && (height(node->lson->rson)>height(node->lson->lson) )) DoubleRotateLR(node); else SingRotateLeft(node); } } else//此节点有1个或0个儿子 { TreeNode<T>* temp = node; if( node->rson ) //有右儿子 { //将右儿子父指针指向原节点父指针 node->rson->parrent = temp->parrent; if( node->parrent ) //父节点存在时,需要将父节点指向该节点的孩子 { if( node->parrent->lson == node ) node->parrent->lson = temp->rson; else node->parrent->rson = temp->rson; } node = temp->rson; } else //有左儿子 或者 为叶子节点 { //将左儿子父指针指向原节点父指针 if( node->lson) node->lson->parrent = temp->parrent; if( node->parrent ) { if( node->parrent->lson == node ) node->parrent->lson = temp->lson; else node->parrent->rson = temp->lson; } node = temp->lson; } delete(temp); temp=NULL; } } //重新计算树高 height(node); } template<class T> void AVLTree<T>::Delete(T x) { DeletePt(root, x); } #endif
然后有测试程序:
#include "BSTree.hpp" const unsigned int MAX = 10; int main() { int arr[MAX] = {0}; unsigned number = 0; BSTree<int> bstree; AVLTree<int> avltree; for ( int index =0 ;index <MAX ; ++index) { //rand_s(&number); number = rand(); arr[index] = number%MAX; cout<<index<<" "<<arr[index]<<endl; bstree.Insert2(arr[index]); avltree.Insert2(arr[index]); } //cout<<"BST"<<endl; //bstree.TraverseTree(); cout<<"AVL:"<<endl; avltree.TraverseTree(); for (int index = 0 ; index < MAX ; ++index) { if( !avltree.Search(arr[index]) ) continue; avltree.Delete(arr[index]); cout<<"删除"<<arr[index]<<"之后"<<endl; avltree.TraverseTree(); } //for (int index = 0 ; index < MAX ; ++index) //{ // if( !bstree.Search(arr[index]) ) // continue; // bstree.Delete(arr[index]); // cout<<"删除"<<arr[index]<<"之后"<<endl; // bstree.TraverseTree(); //} return 1; }
示例结果:
中序遍历的结果,每行数据为(数值,出现次数,节点高度)
下面这个结果中(4,3,2)为根节点,3表示4加入了3此,2表示4的高度为2
初始树结构为:
相关文章推荐
- 平衡二叉查找(AVL)树(C++模板实现)
- 队列——用C++模板实现
- 从零开始学C++之模板(三):缺省模板参数(借助标准模板容器实现Stack模板)、成员模板、关键字typename
- 折半查找的c++模板递归和迭代实现
- C++ 模板实现败者树,进行多路归并
- c++大数、分数、模数运算实现模板
- C++通过模板实现多态
- <C/C++数据结构>散列表(C++模板实现)
- 顺序表 C++模板实现
- 栈(顺序存储)C++模板实现
- 利用C++模板,代替虚函数实现类的静态多态性
- 队列的简介与C++模板实现
- C++ 使用模板 实现单例模式
- 二分查找法(C++ 模板实现)
- 优先级队列 C++ 模板实现
- C++模板应用——让模板定义和实现分离的方法
- 队列(queue) 之 c++模板实现(友元函数和运算符重载)
- 设计模式C++实现(5)——原型模式、模板方法模式
- 栈的简介及C++模板实现
- c++模板实现二叉树,线索化,线索化遍历,非递归遍历及一些基本操作