1 先创建节点类,就是一个普通的节点类的创建,用结构体也可以,唯一值的注意的是要有一个表示当前节点高度的成员,因为节点高度是判断平衡二叉树是否平衡的标志。
#include <iostream>
using namespace std;
template<class T>
class TreeNode
{
public:
T val;
TreeNode<T>* lc;
TreeNode<T>* rc;
int height;
public:
TreeNode(T _val=0,TreeNode<T> *_lc=NULL,TreeNode<T>* _rc=NULL,int _height=0):val(_val), lc(_lc),rc(_rc),height(_height)
{
}
~TreeNode()
{}
TreeNode<T>*Getlc()const{
return lc;
}
// void CreateNode(TreeNode)
void Setlc(TreeNode<T>* _lc);
TreeNode<T>* Getrc() const;
void Setrc(TreeNode<T>* _rc);
void SetVal(T _val);
T GetVal() const
{
return val;
}
bool IsLeaf();
static TreeNode<T>*CreateNode();
};
template<class T>
TreeNode<T>* TreeNode<T>::CreateNode()
{
cout<<"请输入当前节点的值:";
T n;
cin>>n;
if(n<0)
{
return;
}
TreeNode<T> *Node_ptr=new TreeNode<T>(n);
Node_ptr->lc=TreeNode<T>::CreateNode();
Node_ptr->rc=TreeNode<T>::CreateNode();
return Node_ptr;
}
template<class T>
void TreeNode<T>::SetVal(T _val)
{
val=_val;
}
template<class T>
void TreeNode<T>::Setlc(TreeNode<T>* _lc)
{
lc=_lc;
}
template<class T>
void TreeNode<T>::Setrc(TreeNode<T>* _rc)
{
rc=_rc;
}
template<class T>
TreeNode<T>* TreeNode<T>::Getrc() const
{
return rc;
}
接下来是AVL树的创建
1 AVL树的介绍
AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。AVL树得名于它的发明者 G.M. Adelson-Velsky 和 E.M. Landis,他们在 1962 年的论文 "An algorithm for the organization of information" 中发表了它。
其实说白了 AVL树还是一棵二叉查找树(如果不理解什么是二叉查找树一定要先弄懂这个),只不过相对于二叉查找树它多了一个自平衡的特性,就是左右子树的高度差不能大于1,如果大于1了,就要通过旋转来是二叉树重新到达平衡。
下面先看我们实现平衡二叉树类的各种功能,然后我们在一边讲解一边逐一实现。
平衡二叉树的类:
class BalancedBinaryTree
{
private:
TreeNode<T>*subroot;
TreeNode<T>* InsertNode(TreeNode<T>* &_root,T _val);//插入节点
TreeNode<T>* RightHand(TreeNode<T>* &_root); //右旋
TreeNode<T>* LeftHand(TreeNode<T>* &_root); //左旋
TreeNode<T>* RightLeftHand(TreeNode<T>* &_root); //右左
TreeNode<T>* LeftRightHand(TreeNode<T>* &_root); //右左
TreeNode<T>* RemoveNode(TreeNode<T>* _root,T _val);//删除值为_val的节点,返回值是删除后的根节点
TreeNode<T>* MinNode(TreeNode<T>* _root) const;//获取树中的最小值,一直返回左子树的值,直到左子树为空
TreeNode<T>* MaxNode(TreeNode<T>* _root) const;//获取树中的最大值
TreeNode<T>* FindNode(TreeNode<T>*_root,T key) const;//查找值为Key的节点
void DestroyNode(TreeNode<T>* &_root); //销毁树
void TravelPreorderNode(TreeNode<T>* _root) const; //前序遍历-》深度优先遍历
inline int getheight(TreeNode<T> *_Node) const //获取当前节点的高度
{
if(NULL==_Node)
{
return 0;
}
return _Node->height;
}
public:
BalancedBinaryTree(TreeNode<T>* _subroot=NULL):subroot(_subroot)
{}
BalancedBinaryTree(BalancedBinaryTree<T> *Tree)
{
subroot=Tree->GetRoot();
}
~BalancedBinaryTree()
{}
TreeNode<T>* GetRoot() const
{
return subroot;
}
void InsertKey(T _val);
void RemoveKey(T _val);
void DestroyTree(); //销毁树
void TravelPreorderTree() const;
TreeNode<T> * FindKey(T _key);
int TreeHeight() const; //获取树的高度
void TravelInfixorder(TreeNode<T>* _root) const; //中序遍历-》深度优先遍历
void ExtentTravel(TreeNode<T>* _root) const; //广度优先遍历
};
通过上面的代码我们可以看到AVL树的成员函数,在这里要说一下,为什么把所有的函数分为private:和public:这两类,是因为这样符合封装性。再说一下写获取树高度的内联函数的原因,因为在插入或者删除后都要根据左右子树高度差来判断当前AVL树有没有失去平衡。写这个函数最重要的原因是对传入的Node进行了是否为NULL的判断是NULL则返回0,如果写程序的时候直接用Node->lc->height来获取左子树的高度,如果左子树为NULL的话就会报段错误,这种错误编译过程是检查不出来的。
平衡二叉树最重要的就是插入和删除函数,而精髓就是对于四中不平衡情况的旋转&#