您的位置:首页 > 编程语言 > C语言/C++

BST与AVL的C++模板实现

2014-04-18 15:29 477 查看
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;							//频率,默认=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

初始树结构为:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息