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树的构建的主要内容,如果未能解决你的问题,请参考以下文章
BST插值建树re-balance再平衡构建AVL(Adelson-Velskii & Landis)平衡二叉搜索树,基于networkxbinarytree,implement by Pyt