AVL树的构建

Posted scannerkk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AVL树的构建相关的知识,希望对你有一定的参考价值。

一、AVL树简介

  AVL树是一棵自平衡的二叉搜索树,前篇讲过了BST(二叉搜索树),那为什么还需要AVL树呢,因为BST有个缺点,如果我插入的值是单调递增或递减,那么这棵树就会退化成一条链表,有个专业术语也叫作斜树,这会导致原来logn的搜索插入效率编程O(n),为了防止这种退化,就产生了AVL树,当然还有RBT(红黑树),这期我就来总结一下我对于AVL树的想法。

 

二、构建AVL树的操作

  AVL树也是一棵二叉搜索树,所以他的构建过程与二叉搜索树的构建过程十分类似,只是我们在插入的时候要判断是否平衡,所谓平衡就是某个节点的左右子树高度差不超过1,如果超过1我们就需要调整。

  

  第一个操作RR

  首先我们分析1,2,3,4,5,的情况

  树图为

  

 

   这也是我们首先要解决的第一种情况,也称为RR型,我们观察到3的右孩子高度为2,左孩子没有(高度为0),所以失衡了,那么就需要调整,怎么调整呢?--------左旋,所谓左旋就是把需要调整的那个节点放下来,把他的右孩子放上去。

  

 

   这样子就保持了二叉搜索树的平衡,那么做了哪些操作呢,首先把3的高度下降,就是把4节点的左孩子指针指向3,然后把3连向4的右孩子指针指向4的左孩子就可以了,不过要记得更新旋转的节点的高度,为什么只需要更新这两个节点的高度呢?-------因为我没游动他们的子节点,自然也不会改变他们子节点的高度,所以更新他们的高度就可以了,他们的高度就是左右孩子的最大值+1.

 

  第二个操作LL

  所谓LL就是出现在4,2,7,1节点插入的情况下

  树图为

 

   

 

 

   此时右边发生了失衡,也就是RR型失衡,那么我们把节点左旋,把2拽上去,把4拿下来,也就是把2和4的连线拆掉,然后把2的右指针连向4,再把4的左指针连向2的右指针就行了

  LL后的树图

  

 

 

 

  两种简单的情况都分析完了,那么我们再来分析最后两种难一点的情况

  

  第三个操作LR

  当你插入的数为8,7,10,15,11时,你会发现树图为这样

  

 

   10这个节点失衡了,导致了8也失衡了,我们只需要把10这个节点平衡了,8自然也会好了,所以我们的任务是把10进行平衡,但是无论我们怎样尝试,发现都不可以一次性把10这个节点进行平衡,所以我们尝试把10的右节点向右旋,把11转上去,这样就形成了RR型,接下来进行一次RR就行了。

  

  第一步:把11转上去

  

 

   这不就是我们分析的第一种情况了吗?那么我们直接把10进行RR左旋即可,

  

 

   看他又平衡了!

 

  第四种操作LR

  当我们插入的节点为 5,7,4,2,3时

  树图为

  

 

   同理我们发现4这个节点失衡了,导致了5这个节点也失衡了,所以我们调整4后一定能把5也调整好,那我们怎么调整4呢?前面的RL型两次才能完成这个操作,那么这个LR型也一样,不过顺序是相反的而已,及先把4的左孩子进行右旋LL,把3转上去。

  

 

   这不就是第二种操作吗?然后你直接再对4节点进行LL操作即可调整完毕。注意啊,双旋操作第一次操作是针对他的孩子进行的操作!!!

  然后我们发现进行完LL后,树已经平衡了

  树图为

  

 

   至此我们就分析完了AVL的操作以及构建,至于删除操作,以后再说。。。。。

三、AVL代码实现

  

 #include "bits/stdc++.h"
 using namespace std;
 struct node 
     int val;
     int h = 0;//定义高度初始化为0
     node *lchild = NULL;
     node *rchild = NULL;
 ;
 int getHeight(node *root)//获取节点高度
 
     if(root == NULL)
         return 0;
     return root->h;
 
 node* LLrotation(node *root)//右旋操作
     node *temp = root->lchild;
     root->lchild = temp->rchild;
     temp->rchild = root;
     root->h = max(getHeight(root->lchild),getHeight(root->rchild)) + 1;//旋转的过程中会改变树的高度
     temp->h = max(getHeight(temp->lchild),getHeight(temp->rchild)) + 1;//更新节点的高度
     return temp;
 
 node* RRrotation(node *root)//RR的情况就左旋  拽着不平衡的点旋转
     node *temp = root->rchild;
     root->rchild = temp->lchild;
     temp->lchild = root;
     root->h = max(getHeight(root->lchild),getHeight(root->rchild)) + 1;//更新节点的高度
     temp->h = max(getHeight(temp->lchild),getHeight(temp->rchild)) + 1;
     return temp;
 
 node* LRrotation(node* root)//双旋操作
     root->lchild = RRrotation(root->lchild);
     root = LLrotation(root);
     return root;
 
 node* RLrotation(node *root)//双旋操作
     root->rchild = LLrotation(root->rchild);
     root = RRrotation(root);
     return root;
 
 node* createAvl(node *root,int data)
 
     if(root == NULL)
         root = new node();
         root->val = data;
         root->h = 1;//高度初始化
         return root;
     
     if(root->val <= data)
         root->rchild = createAvl(root->rchild,data);//节点插入操作
         if(getHeight(root->rchild) - getHeight(root->lchild) == 2)//如果右边失去平衡则进行调整,注意调整是在插入节点后调整
             if(data > root->rchild->val)//RR如果插入的值在失衡节点的右边的右边,那就进行左旋操作,也就是RR操作
                 root = RRrotation(root);
             else 
                 root = RLrotation(root);//如果插入的值在失衡节点的右边的左边,那就进行双旋操作,也就是RL操作
             
     
     else if(root->val > data)
         root->lchild = createAvl(root->lchild,data);//节点插入操作
         if(getHeight(root->lchild) - getHeight(root->rchild) == 2)//如果左边失去平衡则进行调整,注意调整是在插入节点后调整
             if(root->lchild->val > data)//如果插入的值在失衡节点的左边的左边,那就进行右旋操作,也就是LL操作
                 root = LLrotation(root);//LL
             else 
                 root = LRrotation(root);//LR  如果插入的值在失衡节点的左边的右边,那就进行双旋操作,也就是LR操作
         
     
     else 
         cout << "Add fail!\\n";
     root->h = max(getHeight(root->lchild),getHeight(root->rchild)) + 1;//当前这个根节点因为新加入的节点也要更新高度
     return root;
 
 void bfs(node *root)//层次遍历
 
     queue <node*> ans;
     ans.push(root);
     while(!ans.empty())
         int len = ans.size();
         for(int i = 0;i < len;i++)
             node *v = ans.front();
             ans.pop();
             cout << v->val << " ";
             if(v->lchild) ans.push(v->lchild);
             if(v->rchild) ans.push(v->rchild);
         
     
 
 void printPre(node *root)//前序遍历
 
     if(root)
         cout << root->val << " ";
         printPre(root->lchild);
         printPre(root->rchild);
     
 
 void printAft(node *root)//后序遍历
 
     if(root)
         printAft(root->lchild);
         printAft(root->rchild);
         cout << root->val << " ";
     
 
 void printMle(node *root)//中序遍历
 
     if(root)
         printMle(root->lchild);
         cout << root->val << " ";
         printMle(root->rchild);
     
 
 int main()//RR LL RL LR已经调试成功
 
     node *root = NULL;
     // root = createAvl(root,8);
     // root = createAvl(root,7);
     // root = createAvl(root,10);
     // root = createAvl(root,15);
     // root = createAvl(root,11);
      root = createAvl(root,3);
      root = createAvl(root,4);
      root = createAvl(root,5);
     cout << "Pre_Order:";
     printPre(root);
     cout << endl;
     cout << "Mid_Order:";
     printMle(root);
     cout << endl;
     cout << "Aft_Order:";
     printAft(root);
     cout << endl;
     cout << "Flr_Order:";
     bfs(root);
     return 0;
 

  

本文来自博客园,作者:scanner,转载请注明原文链接:https://home.cnblogs.com/u/scannerkk/

以上是关于AVL树的构建的主要内容,如果未能解决你的问题,请参考以下文章

数据结构之树篇3——平衡二叉树(AVL树)

❤️数据结构入门❤️(2 - 2)- AVL 树

C++AVL树的实现--详细解析旋转细节

AVL树(动图详解)

C++AVL树的实现--详细解析旋转细节

BST插值建树re-balance再平衡构建AVL(Adelson-Velskii & Landis)平衡二叉搜索树,基于networkxbinarytree,implement by Pyt