AVL(高度平衡的二叉树)
2017-07-10 20:11
357 查看
AVL叫做高度平衡的二叉树,以前老记不住这个名字,现在懂了,AVL它是在BST(平衡的二叉树中衍生过来的),因为BST树可能会出现在高度上规则差距很大的树,毕竟他的规则只是比根结点大的作为根结点的右结点,比根结点小的作为根结点的左树;他在BST树的基础上又增加了一条规则,左右子树在高度上最大的高度差只能是1,所以叫他是高度上平衡的排序树;
以下是AVL树的实现:
(1)插入函数Insert函数:
以下是AVL树的实现:
#pragma once #include<iostream> #include<stack> using namespace std; template<class Type> class AVL; template<class Type> class AVLNode { friend class AVL<Type>; public: AVLNode():data(Type()),leftChild(NULL),rightChild(NULL),bf(0) {} AVLNode(Type d,AVLNode<Type> *left=NULL,AVLNode<Type>*rigth=NULL) :data(d),leftChild(left),rightChild(rigth),bf(0) {} ~AVLNode() {} private: Type data; AVLNode *leftChild; AVLNode *rightChild; int bf; }; template<class Type> class AVL { public: AVL() : root(NULL) {} ~AVL() {} public: bool Insert(const Type &x) { return Insert(root, x); } bool Remove(const Type &x) { return Remove(root, x); } protected: bool Insert(AVLNode<Type>*&t, const Type &x); void RotateR(AVLNode<Type> *&ptr); void RotateL(AVLNode<Type> *&ptr); void RotateRL(AVLNode<Type> *&ptr); void RotateLR(AVLNode<Type> *&ptr); private: AVLNode<Type> *root; };
(1)插入函数Insert函数:
template<class Type> bool AVL<Type>::Insert(AVLNode<Type>*&t, const Type &x) { ///////////////////////////////////////////////////////////
这一部分使用非递归的做法实现BST的插入;这里用到了栈,是因为你每次插入一个节点以后都要修改他的父结点的平衡因子,
并且修改第一个父节点的平衡因子之后再修改他的父父结点的平衡因子,用一个栈有利于记录这个结点插入的时候走过的路径,那么在回溯的时候也就方便了;
stack<AVLNode<Type>*> st; AVLNode<Type> *p = t; AVLNode<Type> *pr = NULL; while(p != NULL) { if(x == p->data) return false; pr = p; st.push(pr); if(x < p->data) p = p->leftChild; else p = p->rightChild; } p = new AVLNode<Type>(x); if(pr == NULL)//这是刚插入根结点的情况; { t = p; return true; } if(x < pr->data) pr->leftChild = p; else pr->rightChild = p;
到此位置,新插入的结点已经与之前的结点建立了联系,插入到他该插入的地方;接下来就要看新结点的插入对他的父节点的平衡因子有何影响; ///////////////////////////////////////////////////////////////////
while(!st.empty()) { pr = st.top(); st.pop(); if(p == pr->leftChild) pr->bf--; else pr->bf++; if(pr->bf == 0) break; if(pr->bf==-1 || pr->bf==1)//倒回去继续查看父结点的平很因子; { p = pr; } else {
///到这一步那肯定就不平衡了,需要调整平衡因子 if(pr->bf < 0) { if(p->bf < 0) { cout<<"RotateR"<<endl; RotateR(pr); } else { cout<<"RotateLR(pr)"<<endl; RotateLR(pr); } } else { if(p->bf > 0) { cout<<"RotateL"<<endl; RotateL(pr); } else { cout<<"RotateRL"<<endl; RotateRL(pr); } } break;//调整完以后一定要直接break; } }
到此位置,不平衡的结点已经调整过来了,但是以root为根结点的二插树的内部已经发生了变换,所以下面就是要将修改好的而插入与他的之前的父节点建立连接;
/////////////////////////////////////////////////////////////////// //目的是把调整过了平衡因子的结点和之前的结点关联起来; if(st.empty()) { //如果栈空了,说明他就是根结点 t = pr; } else { //否则把栈顶元素弹出来,将其连接起来; AVLNode<Type> *q = st.top();//它是原来的父节点 if(pr->data < q->data) q->leftChild = pr; else q->rightChild = pr; } return true; }旋转函数的我觉得简单的方法就是把旋转后的结果写出来,然后在将原来的结点做出相应的调整,并且一定要记得调整平衡因子;
template<class Type> void AVL<Type>::RotateR(AVLNode<Type> *&ptr) { AVLNode<Type> *subR = ptr; ptr = ptr->leftChild; //ptr->rightChild = sub->leftChild ;//造成sub的leftChild有俩个了; subR->leftChild = ptr->rightChild; ptr->rightChild = subR; ptr->bf = subR->bf = 0; } template<class Type> void AVL<Type>::RotateL(AVLNode<Type> *&ptr) { AVLNode<Type> *subL = ptr; ptr = ptr->rightChild; subL->rightChild = ptr->leftChild; ptr->leftChild = subL; ptr->bf = subL->bf = 0; } template<class Type> void AVL<Type>::RotateLR(AVLNode<Type> *&ptr) { AVLNode<Type> *subL = ptr->leftChild; AVLNode<Type> *subR = ptr; ptr = subL->rightChild; subL->rightChild = ptr->leftChild; ptr->leftChild = subL; // ptr的平衡因子没有改 if(ptr->bf <= 0) subL->bf = 0; else subL->bf = -1; subR->leftChild = ptr->rightChild; ptr->rightChild = subR; if(ptr->bf == -1) subR->bf = 1; else subR->bf = 0; ptr->bf = 0; } template<class Type>//一定是从当前不平衡结点初开始旋转; void AVL<Type>::RotateRL(AVLNode<Type> *&ptr) { AVLNode<Type> * subL = ptr;//ptr最终会成为左结点; AVLNode<Type> * subR = ptr->rightChild ;//它会成为右节点; ptr = subR->leftChild ;//最终的头结点 //以下是安排最终的左结点和最终的更结点之间附属结点之间的变化;画图更易理解 subL->rightChild = ptr->leftChild ; ptr->leftChild = subL; if(ptr->bf <= 0) { subL->bf = 0; } else { subL->bf = -1; } //以下安排最终的右结点和根结点他们的附属结点直接的变化,画图更易理解 subR->leftChild = ptr->rightChild ; ptr->rightChild = subR; if(ptr->bf <=0) { subR->bf = -1;//有问题; } else { subR->bf = 0; } ptr->bf = 0; }
相关文章推荐
- c++ AVLTree(高度平衡的搜索二叉树)
- 平衡有序二叉树(AVL Tree)的C++实现
- Balanced Binary Tree 判断二叉树是否是高度相差不超过1的高度平衡的二叉树
- 【剑指offer】判断二叉树是否平衡(左右子树高度差最多为1)
- 高度平衡的二叉树
- 建立平衡二叉树(AVL)
- 二叉树-详解平衡二叉排序树AVL
- 【数据结构】建立和平衡AVL二叉树
- AVL平衡搜索二叉树
- avl 平衡搜索二叉树的旋转图示
- 高度平衡的二叉树——AVLTree
- 判断二叉树是否平衡,计算树的高度
- 【LeetCode101-110】二叉树对称及存储,前序中序遍历生成二叉树,中序后序生成二叉树,数组转化为AVL平衡树,判断二叉树是否平衡
- 【数据结构】AVLTree(高度平衡的二叉搜索树)
- 4-8 求二叉树高度 (20分)
- 二叉树--求二叉树的高度/销毁一颗二叉树
- 数据结构面试题/求二叉树的高度/销毁一棵二叉树-->
- 判断二叉树是否平衡
- 二叉树的各种操作的(递归非递归)的实现,如(递归非递归)先序后序中序层次遍历 二叉树的高度 叶子节点数,所有节点数
- 二叉树(三)二叉树的高度、交换两个子树左右节点