BST与AVL的C++模板实现

来源:互联网 发布:网络综艺节目排行榜 编辑:程序博客网 时间:2024/06/05 09:54

C++实现BSTree与AVLTree

回顾树结构时,本打算写个小程序实现一下练练手。

而作为常见的树结构,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;//频率,默认=1int hg;//高度,默认=0TreeNode* 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;elsetmp = 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;elsepPar->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);}//插入接口2template<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;elsepSuc->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 ( pret->lson ){root = pret->lson;root->parrent= NULL;}else if( pret->rson ){root = pret->rson;root->parrent = NULL;}elseroot = 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;}elsepPar->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;}elsepPar->rson = NULL;}}}delete pret;pret = NULL;return true;}//中序遍历 节点nodetemplate<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;elsepPar->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 的高度 -2k2tmp->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;elsepPar->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);elseDoubleRotateLR(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);elseDoubleRotateRL(node);}//重新 算树高height(node);}else++(node->freq);}//插入接口template<class T>void AVLTree<T>::Insert2(T x){InsertPt(root, x);}//中序遍历 节点nodetemplate<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小于节点的值,就继续在节点的左子树中删除xif( 2 == height(node->rson) - height(node->lson) ){if( node->rson->lson && (height(node->rson->lson)>height(node->rson->rson)) )DoubleRotateRL(node);elseSingRotateRight(node);}}else if(x > node->data){DeletePt(node->rson, x);//如果x大于节点的值,就继续在节点的右子树中删除xif( 2== height(node->lson) - height(node->rson) ){if( node->lson->rson && ( height(node->lson->rson) > height(node->lson->lson) ))DoubleRotateLR(node);elseSingRotateLeft(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);elseSingRotateLeft(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;elsenode->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;elsenode->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

初始树结构为:



0 0
原创粉丝点击