AVL树的实现
来源:互联网 发布:构建开放数据生态圈 编辑:程序博客网 时间:2024/05/20 06:49
AVL树:
AVL树也成为平衡二叉树,它是这样定义的:
一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
1、它的左右子树都是AVL树
2、左子树和右子树高度之差(简称平衡因子)的绝对值不超过1(-1、0、1)
AVL树的插入:
在插入节点后会造成父节点的平衡因子发生改变,需要从下往上更新平衡因子,若某一节点的平衡因子的绝对值大于1,说明以这个结点为根的树已经不平衡,此时就要去通过旋转来让数重新达到平衡状态。
旋转规则:
左单旋:在较高右子树的右侧插入了结点
右单旋:在较高左子树的左侧插入了结点
先左后右:在较高左子树的右侧插入了结点
先右后左:在较高右子树的左侧插入了结点
对于较高子树的理解:
较高子树就是不平衡树中的高度较大的子树。
下面是通过右左旋转达到平衡和通过左旋转达到平衡的例子:
下面是通过左右旋转达到平衡和通过右旋转达到平衡的例子:
通过上面的例子我们可以得到以下结论:
当一棵树不平衡时,如果这棵树根节点和其平衡因子不为0的结点的平衡因子符号相同则通过一次旋转即可重新平衡,否则就需要两次旋转。
根为2,子节点为1,通过左旋转即可平衡
根为2,子节点为-1,通过右左旋转才能平衡
根为-2,子节点为1,通过左右旋转才能平衡
根为-2,子节点为-1,通过右旋转即可平衡
注意:在旋转完成之后记得要把平衡因子修改为适当的值,可以通过画出图片做以分析,得到规律
代码:
#include<iostream>#include<windows.h>using namespace std;template<typename K, typename V>struct AVLTreeNode{ AVLTreeNode() {} AVLTreeNode(const K& _key, const V& _value = V()) : key(_key) , value(_value) , bf(0) , pLeft(NULL) , pRight(NULL) , pParent(NULL) {} K key; V value; int bf; AVLTreeNode *pLeft; AVLTreeNode *pRight; AVLTreeNode *pParent;};template<typename K, typename V>class AVLTree{ typedef AVLTreeNode<K, V> Node;public: AVLTree() :pRoot(NULL) {} bool Inserter(const K& _key) { // Node* pCur = pRoot; Node* parent = NULL; if (NULL == pRoot) { pRoot = new Node(_key); return true; } else { //找到插入位置 while (pCur) { if (pCur->key < _key) { parent = pCur; pCur = pCur->pRight; } else if (pCur->key > _key) { parent = pCur; pCur = pCur->pLeft; } else return false; } //插入结点 pCur = new Node(_key); if (parent->key > _key) { parent->pLeft = pCur; } else parent->pRight = pCur; pCur->pParent = parent; } //自下向上更新平衡因子 while (parent) { //更新当前结点父节点的平衡因子 if (parent->pLeft == pCur) { parent->bf--; } else { parent->bf++; } //如果其父节点的平衡因子为0,则说明达到平衡 if (0 == parent->bf) { break; } //如果是1,则继续向上更新 else if (1 == parent->bf || -1 == parent->bf) { pCur = parent; parent = pCur->pParent; } //不是1,就可能是+-2,此时子树不平衡需要调整 //一旦parent的因子绝对值==2,说明其需要调整,此时较高子树是相对于它而言的 else { //右子树高 if (parent->bf == 2) { //右子树的右侧高 if (pCur->bf == 1) { //左旋转 RotateLeft(parent); break; } //右子树的左侧高 else { //右左旋转 RotateRL(pCur); break; } } //左子树高 else { //左子树的左侧高 if (pCur->bf == -1) { //右旋 RotateRight(parent); break; } //左子树的右侧高 else { //左右旋转 RotateLR(pCur); break; } } } } return true; } bool IsBalanceTree()//判断树是不是AVL树 { return _IsBalanceTree(pRoot); } int Hight()//求书的高度 { return _Hight(pRoot); } void InOrder() { _InOrder(pRoot); cout << endl; }private: bool _IsBalanceTree(Node *pRoot) { if (NULL == pRoot) return true; int left = _Hight(pRoot->pLeft); int right = _Hight(pRoot->pRight); if (pRoot->bf != (right - left) || std::abs(pRoot->bf) > 1) return false; return _IsBalanceTree(pRoot->pLeft) && _IsBalanceTree(pRoot->pRight); } void _InOrder(Node* pRoot) { if (NULL == pRoot) return; _InOrder(pRoot->pLeft); cout << pRoot->key << " "; _InOrder(pRoot->pRight); } int _Hight(Node* pRoot) { if (NULL == pRoot) return 0; if (NULL == pRoot->pLeft && NULL == pRoot->pRight) return 1; int left = _Hight(pRoot->pLeft)+1; int right = _Hight(pRoot->pRight)+1; return left > right ? left : right; } //左旋---->就是用父节点的右孩子去替换父节点,将父节点连接在其右孩子的左侧 void RotateLeft(Node *parent) { Node* pParent = parent->pParent; Node* pSubR = parent->pRight; Node* pSubRL = pSubR->pLeft; //父节点的右链接右孩子的左结点 parent->pRight = pSubRL; //右孩子成为父节点的父节点 parent->pParent = pSubR; //右孩子的左结点存在,更新其父节点 if (pSubRL) pSubRL->pParent = parent; //更新右孩子的父节点和左结点 pSubR->pParent = pParent; pSubR->pLeft = parent; //如果pParent存在 if (pParent) { //说明这是一颗子树 //将右节点连接在pParent的左或者右 if (pParent->pLeft == parent) { pParent->pLeft = pSubR; } else { pParent->pRight = pSubR; } } //pParent不存在,说明父节点是树根 else//这是树根将变为右节点 pRoot = pSubR; //将其平衡因子置0 parent->bf = pSubR->bf = 0; } //右旋 void RotateRight(Node* parent) { Node* pParent = parent->pParent; Node* pSubL = parent->pLeft; Node* pSubLR = pSubL->pRight; parent->pLeft = pSubLR; parent->pParent = pSubL; if (pSubLR) pSubLR->pParent = parent; pSubL->pParent = pParent; pSubL->pRight = parent; if (pParent) { if (pParent->pLeft == parent) pParent->pLeft = pSubL; else pParent->pRight = pSubL; } else { pRoot = pSubL; } parent->bf = pSubL->bf = 0; } //左右旋转 void RotateLR(Node* parent) { //判断其右孩子的平衡因子 int bf = parent->pRight->bf; //parent左旋,parent下降其父节点成为其父节点的父节点 RotateLeft(parent); //parent之前的父节点右旋 RotateRight(parent->pParent->pParent); if (bf == -1) {//说明parent接受了其右孩子的左孩子, parent->pParent->pRight->bf = 1; } else if (1 == bf) { //说明parent的父节点,接受了其右孩子的右孩子 parent->bf = -1; } } //右左旋转 void RotateRL(Node* parent) { int bf = parent->pLeft->bf; RotateRight(parent); RotateLeft(parent->pParent->pParent); if (1 == bf) { parent->pParent->pLeft->bf = -1; } else if (-1 == bf) { parent->bf = 1; } }protected: Node* pRoot;};
阅读全文
0 0
- AVL树的实现
- AVL树的实现
- AVL树的实现
- AVL 树的实现
- AVL树的实现
- AVL树的实现
- AVL树的实现
- AVL树的实现
- AVL树的实现
- AVL树的实现
- AVL树的实现
- AVL树的实现
- AVL树的实现
- AVL树的实现
- AVL树的实现
- AVL树的实现
- AVL树的实现
- AVL树的实现
- NAT(网络地址转换)技术与代理服务器原理
- 爬坑总结———elementary OS 0.4.1 Loki 下引导修复和安装搜狗输入法
- java web week_three_one
- 最长递减子序列 最简单描述
- jdk常用参数
- AVL树的实现
- ANR源码分析之ContentProviderClient Timeout
- 华为S9300 ACL配置实例
- 178.n1-使用自定义MyBitmapUtils,不使用xUtils的BitmapUtils加载图片
- 我的第一博
- JAVA源码解析(5)-java.beans.MethodDescriptor、java.beans.MethodRef
- JDK参数总结
- mysql序列实现
- jdbc-maven添加驱动包