AVL树的插入

在向一棵本来高度平衡的AVL树中插入一个新节点时,如果树中某个结点的平衡因子的绝对值 > 1,则出现了不平衡。设新插入结点为P,从结点P到根节点的路径上,每个结点为根的子树的高度都可能增加1,因此在每执行一次二叉搜索树的插入运算后,都需从新插入的结点P开始,沿该结点插入的路径向根节点方向回溯,修改各结点的平衡因子,调整整棵树的高度,恢复被破坏的平衡性质。

AVL树插入算法:

新节点P的平衡因子为0,但其双亲结点Pr的平衡因子有三种情况:

1、结点Pr的平衡因子为0

在Pr的较矮的子树上插入新节点,结点Pr平衡,其高度没有增加,此时从Pr到根路径上各结点为根的子树的高度不变,即各结点的平衡因子不变,结束平衡化处理。

2、结点Pr的平衡因子的绝对值为1;

插入前Pr的平衡因子为0,插入后以Pr为根的子树没有失去平衡,但该子树的高度增

加,需从该结点Pr向根节点方向回溯,继续查看Pr的双亲结点的平衡性。

3、结点Pr的平衡因子的绝对值为2

新节点在较高的子树插入,需要做平衡化处理:

若Pr = 2,说明右子树高,设Pr的右子树为q

当q的平衡因子为1,执行左单旋转

当q的平衡因子为-1,执行先右后左双旋转

若Pr = -2,说明左子树高,设Pr的左子树为q

当q的平衡因子为-1,执行右单旋转

当q的平衡因子为1,执行先左后右双旋转

具体代码:

#include<iostream>

using namespace std;

template<class K, class V>

struct AVLTreeNode

{

AVLTreeNode<K, V>* _pleft;

AVLTreeNode<K, V>* _pright;

AVLTreeNode<K, V>* _pParent;

K _key;

V _value;

int _bf;

AVLTreeNode(const K& key, const V& value)

:_pleft(NULL)

, _pright(NULL)

,_pParent(NULL)

, _key(key)

,_value(value)

,_bf(0)

{}

};

template<class K, class V>

class AVLTree

{

typedef AVLTreeNode<K, V> Node;

public:

AVLTree()

:_pRoot(NULL)

{}

AVLTree(const AVLTree<K, V>& t);

AVLTree<K, V>& operator=(const AVLTree<K, V>& t);

~AVLTree()

{

_Destory(_pRoot);

}

public:

bool Insert(const K& key, const V& value)

{

if(NULL == _pRoot)

{

_pRoot = new Node(key, value);

return true;

}

//寻找插入位置

Node* parent = NULL;

Node* pCur = _pRoot;

while(pCur)

{

if(key < pCur->_key)

{

parent = pCur;

pCur = pCur->_pleft;

}

else if(key > pCur->_key)

{

parent = pCur;

pCur = pCur->_pright;

}

else

return false;

}

pCur = new Node(key, value);

//插入

if(key < parent->_key)

{

parent->_pleft = pCur;

}

else

{

parent->_pright = pCur;

}

pCur->_pParent = parent;

//更新平衡因子

while(parent)

{

if(parent->_pleft == pCur)

{

parent->_bf--;

}

else

{

parent->_bf++;

}

if(parent->_bf == 0)

{

break;

}

else if(1 == parent->_bf || parent->_bf == -1)

{

pCur = parent;

parent = pCur->_pParent;

}

else

{

if(parent->_bf == 2)

{

if(pCur->_bf == 1)

_RotateL(parent);

else if(pCur->_bf == -1)

_RotateRL(parent);

}

else if(parent->_bf == -2)

{

if(pCur->_bf == -1)

_RotateR(parent);

else if(pCur->_bf == 1)

_RotateLR(parent);

}

break;

}

}

return true;

}

void Inorder()     //中序遍历

{

_Inorder(_pRoot);

cout << endl;

}

bool IsBalance()    //判断是否平衡

{

int height = 0;

return _IsBalance(_pRoot, height);

}

private:

void _RotateR(Node* parent)

{

Node* subL = parent->_pleft;

Node* subLR = subL->_pright;

parent->_pleft = subLR;

if(subLR)

subLR->_pParent = parent;

subL->_pright = parent;

Node* pParent = parent->_pParent;

parent->_pParent = subL;

if(pParent == NULL)

{

_pRoot = subL;

subL->_pParent = NULL;

}

else

{

if(pParent->_pleft == parent)

{

pParent->_pleft = subL;

}

else

{

pParent->_pright = subL;

}

subL->_pParent = pParent;

}

subL->_bf = parent->_bf = 0;

}

void _RotateL(Node* parent)

{

Node* subR = parent->_pright;

Node* subRL = subR->_pleft;

parent->_pright = subRL;

if(subRL)

subRL->_pParent = parent;

subR->_pleft = parent;

Node* pParent = parent->_pParent;

parent->_pParent = subR;

if(pParent == NULL)

{

_pRoot = subR;

subR->_pParent = NULL;

}

else

{

if(pParent->_pleft == parent)

{

pParent->_pleft = subR;

}

else

{

pParent->_pright = subR;

}

subR->_pParent = pParent;

}

subR->_bf = parent->_bf = 0;

}

void _RotateRL(Node*& parent)

{

Node* subR = parent->_pright;

Node* subRL = subR->_pleft;

_RotateR(subR);

_RotateL(parent);

int bf = subRL->_bf;

if (bf == 0)

{

subRL->_bf = parent->_bf = subR->_bf = 0;

}

else if (bf == -1)

{

subRL->_bf = 0;

parent->_bf = 1;

subR->_bf = 0;

}

else if (bf == 1)

{

subRL->_bf = 0;

parent->_bf = 0;

subR->_bf = 1;

}

}

void _RotateLR(Node*& parent)

{

Node* subL = parent->_pleft;

Node* subLR = subL->_pright;

_RotateL(subL);

_RotateR(parent);

int bf = subLR->_bf;

if (bf == 0)

{

subLR->_bf = parent->_bf = subL->_bf = 0;

}

else if (bf == 1)

{

subLR->_bf = 0;

parent->_bf = 1;

subL->_bf = 0;

}

else if (bf == -1)

{

subLR->_bf = 0;

parent->_bf = 0;

subL->_bf = -1;

}

}

void _Destory(Node*& pRoot)

{

if (_pRoot == NULL)

return;

_Destory(pRoot->_pleft);

_Destory(pRoot->_pright);

delete pRoot;

pRoot = NULL;

}

protected:

void _Inorder(Node* pRoot)     //中序

{

if (pRoot == NULL)

{

return;

}

_Inorder(pRoot->_pleft);

cout << pRoot->_key << " ";

_Inorder(pRoot->_pright);

}

bool _IsBalance(Node* pRoot, int& height)

{

if (pRoot == NULL)

{

height = 0;

return true;

}

int left, right;

if (_IsBalance(pRoot->_pleft, left) && _IsBalance

(pRoot->_pright, right)

&& abs(right - left) < 2)

{

height = left > right ? left + 1 : right + 1;

if (pRoot->_bf != right - left)

{

cout << "平衡因子异常:" << pRoot->_key

<< endl;

return false;

}

return true;

}

else

{

return false;

}

}

size_t _Height(Node* pRoot)    //高度

{

if (pRoot == NULL)

{

return 0;

}

int l = _Height(pRoot->_pleft);

int r = _Height(pRoot->_pright);

return l > r ? l + 1 : r + 1;

}

private:

Node* _pRoot;

};

int main()

{

AVLTree<int, int> t;

t.Insert(3,3);

t.Insert(7,7);

t.Insert(11,11);

t.Insert(14,14);

t.Insert(15,15);

t.Insert(18,18);

t.Insert(16,16);

t.Insert(26,26);

t.Insert(9,9);

t.Inorder();

cout << "IsBalance? " << t.IsBalance() << endl;

system("pause");

return 0;

}

平衡二叉查找树插入节点操作( AVLTree ):旋转、调整平衡相关推荐

  1. 双链表(插入节点操作)

    在双链表L中第i个位置插入值域为e的结点. 双链表的存储结构定义: typedef struct DLinkList{int data;DLinkList * prior;DLinkList * ne ...

  2. java二叉树插入节点_[javaSE] 数据结构(二叉查找树-插入节点)

    public class BSTree>{private BSTNodemRoot;/*** 定义二叉树 * *@authortaoshihan *@param **/ public class ...

  3. Algorithm:树相关算法(BBT/BST/B树/R树)简介(二叉查找树、二叉查找树的插入节点、二叉查找树的删除、二叉树的遍历、平衡二叉树)C 语言实现

    Algorithm:树相关算法(BBT/BST/B树/R树)简介(二叉查找树.二叉查找树的插入节点.二叉查找树的删除.二叉树的遍历.平衡二叉树)C++语言实现 目录 树的基础知识 1.二叉树的遍-前序 ...

  4. 【AVL树】AVL树的插入操作以及旋转

    在讲解AVL树之前必须了解二叉搜索树, 可以看我之前的博客:二叉搜索树 AVL树是在二叉搜索树的基础上,在向二叉树排序树中插入新的结点,如果保证每个结点的左右子树的高度差的绝对值不超过1,即需要在插入 ...

  5. Java之HashMap经典算法-红黑树(插入节点平衡调整,左旋转,右旋转)

    1. 红黑树的优势 有了二叉搜索树,为什么还需要平衡二叉树? 二叉搜索树容易退化成一条链,这时,查找的时间复杂度从 O(log2N)O(log_2N)O(log2​N) 将退化成 O(N)O(N )O ...

  6. 超简单理解自平衡二叉查找树的 旋转 是什么?

    首先给大家科普下基础知识 (双旋转的时候,LR左右,RL右左,且首转以尾根节点为旋转中心,第二次旋转以尾根节点的父节点为旋转中心) 一:什么情况下二叉查找树不平衡? 答:一个节点的左子树与右子树的高度 ...

  7. jquery的DOM节点操作(创建和插入元素节点)

    1.创建元素节点 2.插入节点 动态创建新元素节点后,需要执行插入或追加操作,否则不会在页面显示出来. 按照元素的层次关系来分,可以分为内部和外部两种方法 元素内部插入子节点 元素内部插入子节点有两种 ...

  8. jquery 元素节点操作 - 创建节点、插入节点、删除节点

    jquery的节点操作说明 前面的篇章对于jquery的元素操作大部分是使用html()的方式来操作,这种直接使用字符串创建的方式也是性能最高的. 使用html()操作节点 首先编写一个div包含一个 ...

  9. java document创建节点_javasript 的DOM 节点操作:创建,插入,删除,复制以及查找节点...

    DOM 含义: DOM 是文档对象模型(Document Object Model) 是一种基于浏览器编程的一套API 接口,我W3C 出台推荐的标准.其赋予了JS 操作节点的能力,当网页被加载时,浏 ...

最新文章

  1. :before和::before的区别
  2. 自动驾驶中,激光雷达点云如何做特征表达
  3. 在 Java 的反射中,Class.forName 和 ClassLoader 的区别
  4. 7-zip来解压大于4G以上打包文件
  5. php分页代码 页数太多,php google或baidu分页代码
  6. 小小总结一下目前的财政
  7. python获取类的类属性_Python中如何获取类属性的列表
  8. 由.Net类库提供的农历计算(C#农历)
  9. 也说说angularJs里的evalAsync
  10. C#中手动引用COM组建的例子
  11. 搭建自已的聊天服务器Rocket.Chat
  12. 2012-11-25 3:00 发喜讯,终于把S5pv210 VGA 分辨率提升到1440 x 900/1920 x 1080了!
  13. 英语听力软件测试自学,每日英语听力应该怎么学习?
  14. Android 蓝牙HOGP协议(基于ble-gatt蓝牙)连接流程分析--framework-jni-btif-bta-btm-hci -- 全网最详细(二)
  15. 计算机系统启动项设置密码,电脑开机第一道密码怎么设置 - 卡饭网
  16. react插件,树状图(可自由定义子节点结构,大小,样式)
  17. 网页设计的秘诀:如何用颜色烘托情感
  18. 数据分析之excel和finebi报表可视化对比
  19. 为什么Microsoft账号登录显示暂时停用你的账户_苹果手机显示 Apple ID 被停用该如何恢复?...
  20. H3CSE路由-IPv6路由协议

热门文章

  1. ASP.NET状缓存Cache的应用-提高数据库读取速度
  2. 最长公共子序列|最长公共子串|最长重复子串|最长不重复子串|最长回文子串|最长递增子序列|最大子数组和...
  3. 告诉你银行在年底为存储做的小动作
  4. 农业部部署农业大数据发展工作 评:对农业现代化很重要
  5. FB宣布将回购60亿美元股票 首席会计官将离职
  6. Ios: 如何保護iOS束文件屬性列表,圖像,SQLite,媒體文件
  7. android传递数据bundle封装传递map对象
  8. 替换WordPress调用的Google前端库为360镜像的库
  9. 5shift shell
  10. Unique Binary Search Trees