AVL树

来源:互联网 发布:淘宝店铺商品详情模板 编辑:程序博客网 时间:2024/06/06 03:08

Q0:向根结点为head的AVL树的左子树中插入一个节点后,可能同时导致head和head -> left 失去平衡,为什么只要调整head -> left 使以head -> left为根节点的左子树达到平衡就能使head达到平衡?

Q1:当向某个节点插入一个节点后,如果该节点失去平衡(即以该节点为根节点的树失去平衡,不再是AVL树),那么在调整该节点时,其子孙节点是否有被调整过?


A0:假设first是第一个失去平衡的节点(first节点的子孙节点都是平衡的),那么first失去平衡无非就是左子树高了,或者右子树高了。下面的四种情况穷举了所有导致first节点失去平衡的插入情况。插入之前,以first为根节点的AVL树的高度是H+2,旋转调整之后,以first为根节点的AVL树的高度仍为H+2,所以first的父节点仍然是平衡的,同理可推出first的所有祖先节点都是平衡的。

case one:左子树高了

左子树高了,意味着左子树的高度比右子树高2,说明在插入新节点之前左子树的高度比右子树高1。根据插入的新节点的插入位置可以再分两种情况,一是新节点插入在失去平衡的first节点的左孩子的左子树(即LL插入),二是新节点插入在first的左孩子的右子树(即LR插入)

LL:在插入节点1后,first节点第一个失去平衡,需要对first节点进行右旋转(顺时针方向旋转)


LR:在插入节点7后,first节点第一个失去平衡,需要对first节点进行左右旋转(先对first -> left进行左旋转(逆时针方向旋转),再对first进行右旋转(顺时针方向旋转))


case two:右子树高了

右子树高了,意味着右子树的高度比左子树高2,说明在插入新节点之前右子树的高度比左子树高1。根据插入的新节点的插入位置可以再分两种情况,一是新节点插入在失去平衡的first节点的右孩子的左子树(即RL插入),二是新节点插入在first的右孩子的右子树(即RR插入)

RL:在插入节点5后,first节点第一个失去平衡,需要对first节点进行右左旋转(先对first -> right进行右旋转(顺时针方向旋转),再对first进行左旋转(逆时针方向旋转))

RR:插入节点9后,first节点第一个失去平衡,需要对first进行左旋转(逆时针方向旋转)


A1:当某个节点A失去平衡需要被调整时,其子孙节点一定是平衡的,没有被调整过的。因为根据A1中的四种调整情况,如果其子孙节点有被调整过,那么其子孙节点的祖先节点一定是平衡的,即节点A是平衡的,而如果节点A不平衡,则其子孙节点都是未被调整过的。

先把所有的元素建成一棵树,然后再判断这棵树是否是AVL树是很难的。AVL树的建立就是通过在一棵已经是AVL的树上插入一个新节点,然后再判断插入新节点后该树是否还是AVL,如果不是,则进行相应的调整。由于在插入新节点之前,该树已经是AVL树,那么插入新元素之后,如果不再是AVL树,则要么是根节点的左子树高了,那么是根节点的右子树高了。因此,我们可以穷举出导致原AVL树失去平衡的总共只有四种插入方法,对这四种插入方法,分别有四种调整方法使新的树变成AVL树。

AVL树的建立是一个递归的过程,假设head是一棵AVL树的根结点,当向head插入一个新的节点时,如果插入到head的左子树中,那么在对head节点进行调用时,会先对head->left进行调整,使得以head->left为根节点的左子树是一棵AVL树;然后再对head进行调整。旋转是针对某个节点做的,即调整以该节点为根节点的树使之成为AVL树。

两个有用链接

http://zh.wikipedia.org/wiki/AVL%E6%A0%91

http://blog.csdn.net/collonn/article/details/20128205

LL 插入:左旋转,对应附录代码中的函数 left_rotate

RR 插入:右旋转,对应附录代码中的函数 right_rotate

LR 插入:左右旋转 ,对应附录代码中的函数left_right_rotate

RL 插入:右左旋转 ,对应附录代码中的函数right_left_rotate

备注:旋转时,是低位(深度大)节点保持不动,高位节点旋转。左旋转是逆时针方向旋转,右旋转是顺时针方向旋转。



附录:本人实现的AVL树

#include <queue>int max(int a, int b){if(a > b)return a;return b;}struct node{node* left;node* right;int data;};class AVL{public:AVL();template<class InputIterator>AVL(InputIterator first, InputIterator last);void insert(int value);void display();protected:node* insert_aux(node* head, int value);int height(node* head);node* left_rotate(node* head);node* right_rotate(node* head);node* left_right_rotate(node* head);node* right_left_rotate(node* head);private:node* head;};AVL::AVL(){head = 0;}template<class InputIterator>AVL::AVL(InputIterator first, InputIterator last){while(first != last){head = insert_aux(head, *first);first++;}}void AVL::insert(int value){head = insert_aux(head, value);}// 层次输出,- 表示该节点为空void AVL::display(){std::queue<node*> q;q.push(head);while(!q.empty()){if(q.front() != 0){std::cout << q.front() -> data << ' ';q.push(q.front() -> left);q.push(q.front() -> right);}elsestd::cout << "- ";q.pop();}}/** * @brief: 该函数向根节点为head的AVL树中插入value,得到一棵新的AVL树 * @pre_condition: head必须是一棵AVL树 * @post_condition: 返回的也是一棵AVL树 * @param head: head是插入value前的AVL树的根节点 * @param value: value是被插入的值 * @return: 返回是的新的AVL树的根节点*/node* AVL::insert_aux(node* head, int value){if(head == 0){head = (node*)malloc(sizeof(node));head -> data = value;head -> left = head -> right = 0;return head;}if(value == head -> data)return head;if(value < head -> data){// insert_aux(head -> left, value)会在head -> left树中插入一个新节点// 并调整head -> left为根的树使之成为AVL树,再返回调整后得到的AVL树的根节点head -> left = insert_aux(head -> left, value);if(height(head -> left) > height(head -> right) + 1) // head is unbalanced {if(value < head -> left -> data)head = right_rotate(head);// (1) LLelsehead = left_right_rotate(head); // (3) LR}}else{head -> right = insert_aux(head -> right, value);if(height(head -> left) + 1 < height(head -> right)){if(value < head -> right -> data)head = right_left_rotate(head);// (4) RLelsehead = left_rotate(head);// (2) RR}}return head;}int AVL::height(node* head){if(head == 0)return 0;return 1 + max(height(head -> left), height(head -> right));}/* * @brief: 左旋转,即逆时针旋转,对应 RR 插入 *         旋转是针对某棵树的操作,即针对某个根节点的操作*/node* AVL::left_rotate(node* head){node* nhead = head -> right;head -> right = nhead -> left;nhead -> left = head;return nhead;}/* * @brief: 右旋转,即顺时针旋转,对应 LL 插入*/node* AVL::right_rotate(node* head){node* nhead = head -> left;head -> left = nhead -> right;nhead -> right = head;return nhead;}/* * @brief: 左右旋转,先左旋转,再右旋转,对应 LR 插入*/node* AVL::left_right_rotate(node* head){head -> left = left_rotate(head -> left);node* nhead = right_rotate(head);return nhead;}/* * @brief: 右左旋转,先右旋转,再左旋转,对应 RL 插入*/node* AVL::right_left_rotate(node* head){head -> right = right_rotate(head -> right);node* nhead = left_rotate(head);return nhead;}

测试程序

int main() { int a[] = {8,7,2,9,0,1,3,6,4,20,14,24,5};AVL tree(a, a + sizeof(a) / 4);tree.display();cout << endl;    return (0); }


0 0
原创粉丝点击