BST是一种可以实现快速查找的有序数据结构,但其性能受输入元素顺序的影响,比如输入9,8,7,6这样的有序序列,得到的就是一颗极不平衡的二叉树,甚至退化至单链表。为了改善这一点,延伸出了许多以其为基础的二叉树,如红黑树,AVL数,SB树等,他们的区别在于平衡的标准不一,接下来我们探讨下其中的AVL树。
AVL树判断平衡的标准很简单,就是该节点左右子树的高度差要不大于1,若是不满足,则进行相应的位置调整。可以列出如下不平衡的四种情况,红色的点即为不满足要求的点。
对于RR和LL型,需要分别进行左旋和右旋。而对于RL型则要先右旋再左旋,对于LR型要先左旋再右旋。旋转过程相对简单,代码如下。
treenode<T> *leftrotation(treenode<T> * cur){
treenode<T> *tmp = cur->right;
cur->right = tmp->left;
tmp->left = cur;
return tmp;
}
treenode<T> *rightrotation(treenode<T> *cur){
treenode<T> *tmp = cur->left;
cur->left = tmp->right;
tmp->right = cur;
return tmp;
}
treenode<T> *leftrightrotaion(treenode<T> *cur)
{
cur->left = leftrotation(cur->left);
return rightrotation(cur);
}
treenode<T> *rightleftrotaion(treenode<T> *cur)
{
cur->right = rightrotation(cur->right);
return leftrotation(cur);
}
插入
由于每次有节点插入时,都会检测平衡条件作出调整,所以插入后破坏平衡的情况只有上述的四种情况。以递归的方式找到插入节点的位置,再在返回的途中不断检测节点的平衡条件是否满足,不满足则根据情况采取相应的旋转措施。
treenode<T> *insert(treenode<T> *cur, T data){
if(cur==NULL)
return new treenode<T>(data);
else if(data>cur->data){
cur->right = insert(cur->right,data);
if(getheight(cur->right)-getheight(cur->left)==2)
{
if(data>cur->right->data)//situation RR
cur = leftrotation(cur);
else if(data<cur->right->data)//RL
cur = rightleftrotaion(cur);
}
}else if(data<cur->data){
cur->left = insert(cur->left,data);
if(getheight(cur->left)-getheight(cur->right)==2)
{
if(data<cur->left->data)//LL
cur = rightrotation(cur);
else if(data>cur->left->data)//LR
cur = leftrightrotaion(cur);
}
}
return cur;
}
删除
同BST,当删除的节点左右节点不为空,则选择左树上的最右节点或者右树上的最左结点来顶替该删除的结点。若左右树只有其中一个节点不为空,则直接用不为空的节点顶替要删除的节点。删除过后需要重新判定平衡条件,同插入。
treenode<T> *remove(treenode<T> *cur, T data){
if(cur==NULL)
return NULL;
if(cur->data==data){//找到要删除的结点
if(cur->right&&cur->left){//左右节点不为空
if(getheight(cur->left)>getheight(cur->right)){
treenode<T>*tmp = getmax(cur->left);
cur->data = tmp->data;
cur->left = remove(cur->left,tmp->data);
}else{
treenode<T>*tmp = getmin(cur->right);
cur->data = tmp->data;
cur->right = remove(cur->right,tmp->data);
}
}else{
treenode<T>*tmp = cur;
if(cur->left==NULL)
cur = cur->right;
else if(cur->right==NULL)
cur = cur->left;
delete tmp;
return cur;
}
}else if(cur->data>data){
cur->left = remove(cur->left,data);
if(getheight(cur->right)-getheight(cur->left)==2)
{
if(getheight(cur->right->left)>getheight(cur->right->right))
cur = rightleftrotaion(cur);
else
cur = leftrotation(cur);
}
}else if(cur->data<data){
cur->right = remove(cur->right,data);
if(getheight(cur->left)-getheight(cur->right)==2)
{
if(getheight(cur->left->right)>getheight(cur->left->left))
cur = leftrightrotaion(cur);
else
cur = rightrotation(cur);
}
}
return cur;
}
查找,遍历打印等同BST。
完整代码
template<typename T>
struct treenode{
T data;
treenode<T> *left;
treenode<T> *right;
treenode(T a,treenode<T> *l = NULL,treenode<T> *r = NULL):data(a),left(l),right(r){}
};
template<typename T>
class AVLTree
{
private:
treenode<T> *head;
void destroybst(treenode<T> *Node){
if(Node==NULL)
return ;
destroybst(Node->left);
destroybst(Node->right);
std::cout<<"delete point "<<std::to_string(Node->data)<<std::endl;
delete Node;
}
treenode<T> *insert(treenode<T> *cur, T data){
if(cur==NULL)
return new treenode<T>(data);
else if(data>cur->data){
cur->right = insert(cur->right,data);
if(getheight(cur->right)-getheight(cur->left)==2)
{
if(data>cur->right->data)//situation RR
cur = leftrotation(cur);
else if(data<cur->right->data)//RL
cur = rightleftrotaion(cur);
}
}else if(data<cur->data){
cur->left = insert(cur->left,data);
if(getheight(cur->left)-getheight(cur->right)==2)
{
if(data<cur->left->data)//LL
cur = rightrotation(cur);
else if(data>cur->left->data)//LR
cur = leftrightrotaion(cur);
}
}
return cur;
}
treenode<T> *remove(treenode<T> *cur, T data){
if(cur==NULL)
return NULL;
if(cur->data==data){
if(cur->right&&cur->left){
if(getheight(cur->left)>getheight(cur->right)){
treenode<T>*tmp = getmax(cur->left);
cur->data = tmp->data;
cur->left = remove(cur->left,tmp->data);
}else{
treenode<T>*tmp = getmin(cur->right);
cur->data = tmp->data;
cur->right = remove(cur->right,tmp->data);
}
}else{
treenode<T>*tmp = cur;
if(cur->left==NULL)
cur = cur->right;
else if(cur->right==NULL)
cur = cur->left;
delete tmp;
return cur;
}
}else if(cur->data>data){
cur->left = remove(cur->left,data);
if(getheight(cur->right)-getheight(cur->left)==2)
{
if(getheight(cur->right->left)>getheight(cur->right->right))//situation RR
cur = rightleftrotaion(cur);
else
cur = leftrotation(cur);
}
}else if(cur->data<data){
cur->right = remove(cur->right,data);
if(getheight(cur->left)-getheight(cur->right)==2)
{
if(getheight(cur->left->right)>getheight(cur->left->left))//situation RR
cur = leftrightrotaion(cur);
else
cur = rightrotation(cur);
}
}
return cur;
}
int getheight(treenode<T> *p){
if(p==NULL)
return 0;
int left = 1 + getheight(p->left);
int right = 1 + getheight(p->right);
return max(left,right);
}
treenode<T> *getmin(treenode<T> *p){
treenode<T> *tmp = p;
while(tmp->left!=NULL)
tmp = tmp->left;
return tmp;
}
treenode<T> *getmax(treenode<T> *p){
treenode<T>* tmp = p;
while(tmp->right!=NULL)
tmp = tmp->right;
return tmp;
}
treenode<T> *leftrotation(treenode<T> * cur){
treenode<T> *tmp = cur->right;
cur->right = tmp->left;
tmp->left = cur;
return tmp;
}
treenode<T> *rightrotation(treenode<T> *cur){
treenode<T> *tmp = cur->left;
cur->left = tmp->right;
tmp->right = cur;
return tmp;
}
treenode<T> *leftrightrotaion(treenode<T> *cur)
{
cur->left = leftrotation(cur->left);
return rightrotation(cur);
}
treenode<T> *rightleftrotaion(treenode<T> *cur)
{
cur->right = rightrotation(cur->right);
return leftrotation(cur);
}
public:
AVLTree(T data){
head = new treenode<T>(data);
}
void node_insert(T data){
head = insert(head,data);
}
void node_remove(T data)
{
remove(head,data);
}
void preprintf(treenode<T> *Node){
if(Node==NULL)
return ;
stack<treenode<T> *> list;
treenode<T> *p = Node;
while(!list.empty() || p!=NULL){
while(p)
{
cout<<p->data<<" ";
list.push(p);
p = p->left;
}
p = list.top();
list.pop();
p = p->right;
}
cout<<endl;
}
void backprintf(treenode<T> *Node){
if(Node == NULL)
return ;
treenode<T> *cur = Node;
treenode<T> *flag = NULL;
stack<treenode<T> *> list;
while(cur)
{
list.push(cur);
cur = cur->left;
}
while(!list.empty())
{
cur = list.top();
list.pop();
if(cur->right==NULL || cur->right == flag)
{
cout<<cur->data<<" ";
flag = cur;
}else{
list.push(cur);
cur = cur->right;
while(cur)
{
list.push(cur);
cur = cur->left;
}
}
}
return ;
}
treenode<T> * findnode(T data){
treenode<T> * tmphead = head;
while(tmphead!=NULL)
{
if(tmphead->data==data)
return tmphead;
else{
if(data>tmphead->data)
tmphead = tmphead->right;
else
tmphead = tmphead->left;
}
}
return NULL;
}
~AVLTree(){
destroybst(head);
}
treenode<T> * gethead(){
return head;
}
};
void AVLtest()
{
AVLTree<int> test(10);
test.node_insert(9);
test.node_insert(6);
test.node_insert(17);
test.node_insert(18);
test.preprintf(test.gethead());
test.node_remove(9);
test.node_remove(17);
test.preprintf(test.gethead());
}
int main()
{
AVLtest();
return 0;
}