平衡二叉树(AVL)(一)
来源:互联网 发布:窥一隅而知全貌的意思 编辑:程序博客网 时间:2024/06/06 12:24
平衡二叉搜索树是具有某些特殊性质的二叉搜索树,对于每一个节点 p , 它的左右子树的高度相差不超过 1。将二叉排序树维持在平衡状态。因此查找,删除,插入的操作的时间复杂度维持在
查找元素,遍历,找最大最小值,求树的高度,这些基本操作和普通的二叉搜索树几乎一样,直接借用二叉搜索树的成员函数,具体实现何以参见
二叉搜索树
对其进行插入元素时,首先按照普通的二叉搜索树插入,但是插入元素之后可能导致叶子节点的高度差大于1,这时候需要进行节点的旋转,恢复平衡二叉树的性质。
如下图插入键值为 7 节点,很显然新的排序二叉树的不再满足平衡二叉树的性质。
旋转
由于任意节点最多有两个儿子,高度不平衡时,此节点的两颗子树的高度相差2,有以下几种情况:
case1:左左情况 13 节点的左子树 8节点 的高度比右子树 15节点 的高度大 2, 左子树 8节点的 左子树 5节点 的高度大于 右子树 10节点
case2:左右情况 13 节点的左子树 8节点 的高度比右子树 15节点 的高度大 2, 左子树 8节点的 右子树 10节点 的高度大于 右子树 5节点
case3:右左情况 9 节点的右子树 15节点 的高度比左子树 8节点 的高度大 2, 右子树 15节点的 左子树 12节点 的高度大于 右子树 18节点
case3:右右情况 9 节点的右子树 15节点 的高度比左子树 8节点 的高度大 2, 右子树 15节点 的右子树 18节点 的高度大于 左子树 12节点
单旋转:
case1 和 case4 属于对称情况,只需要一次旋转就可以,下面分析case1 左左情况 singRotateLeft(k1) :(节点k1 不符合平衡二叉树的性质)
由对称性对于case4执行 singRotateRight(K1)。
void avlTree::singRotateLeft(Node *p) // case1:左左情况左旋{ Node *pLchild = p->lchild; this->transplant(p, pLchild); p->lchild = pLchild->rchild; if (pLchild->rchild) // 可能待左转节点的左孩子没有右孩子 { pLchild->rchild->parent = p; } pLchild->rchild = p; p->parent = pLchild;}void avlTree::singRotateRight(Node *p) // case4:右右情况{ Node *pRchild = p->rchild; this->transplant(p, pRchild); p->rchild = pRchild->lchild; if (pRchild->lchild) // 可能待右转节点的右孩子没有左孩子 { pRchild->lchild->parent = p; } pRchild->lchild = p; p->parent = pRchild;}
// 移植节点 void transplant(Node* oldNode, Node* newNode); // 移植节点
参见二叉搜索树 里的具体实现。
http://blog.csdn.net/lmx2014001/article/details/52072784
双旋转
case2 和 case3 属于对称情况,下面分析 case 2:(节点k1 不符合平衡二叉树的性质)
先以节点 k2 = k1-> lchild为研究对象进行一次 右右情况的旋转,singRotateRight(Node *p),将问题转化为 case1,然后在case1 情况下,再经过左左情况的旋转 singRotateLeft(k1)。
void avlTree::doubleRotateLR(Node *p) // case2:左右情况{ this->singRotateRight(p->lchild); this->singRotateLeft(p);}void avlTree::doubleRotateRL(Node *p) // case3:右左情况{ this->singRotateLeft(p->rchild); this->singRotateRight(p);}
插入节点
插入节点分两步:
第一步,和普通的二叉排序树相同的步骤插入;
第二步,从插入新节点的父亲开始,沿着走向根节点的简单路径,不断检查是否满足平衡二叉树的性质。
在描述具体检测步骤之前,先引入 任意节点 p 的平衡因子,即该节点 p 的左子树高度与右子树高度之差,具体实现如下:
易知
int Node::getBFac(){ return this->lchild->getHight() - this->rchild->getHight();}
详细检查及恢复步骤:
1. 求得新插入节点 N 的的父亲结点 p 的平衡因子
case1,2不会改变以 父亲结点 p 为根节点的子树的高度,因此不会破坏整棵树的平衡性质。不需要进一步检测!
case3,4使父亲结点 p 为根节点的子树的高度由 1 (只有一个根节点 p)增加到了 1,因此可能破坏整棵树的平衡性质。需要进行下一步检测。
新插入节点N的父亲节点 p 的平衡因子为 1 时,进一步检查 节点N 的祖父节点G,如果
G−>getBFac() 为2 或者 -2 ,则找到问题节点,并对其进行旋转操作,不再继续向上检测问题节点;如果G−>getBFac()=0 时才可以确定新插入节点并没有影响整棵树的平衡性质,则停止检查,不需要维护了;G−>getBFac() 为1 或者 -1, 则将可能出现的问题点上移。不断重复步骤 2,直到不断上升的祖父节点 G 越过根节点变为 NULL。
void avlTree::insertAvlNode(int newValue){ Node *newNode = new Node(newValue); Node *p, *tempParent = new Node(), *tempGrandpa = new Node(), *tempuncle = new Node(); int parentFac, GrandpaFac; if (this->getSize() == 0) { this->root = newNode; } else { p = this->root; while (p) { // 保存父亲结点,万一他的孩子为空,跳出循环后还可以翻出来 tempParent = p; if (newValue > p->data) { p = p->rchild; } else { p = p->lchild; } } newNode->parent = tempParent; if (newValue > tempParent->data) { tempParent->rchild = newNode; } else { tempParent->lchild = newNode; } // 以上步骤各普通的二叉排序树插入节点一样 parentFac = tempParent->getBFac(); if (parentFac) // 新插入节点的父节点 tempParent 平衡因子为非零,则tempParent 的高度肯定增加了 1,由原先的 0 变为1 { int rFlag = 0; // 标记是否旋转,最多只需要旋转一次(doubleRotate 也算一次) tempGrandpa = tempParent->parent; while (tempGrandpa && !rFlag) { GrandpaFac = tempGrandpa->getBFac(); if (!GrandpaFac) { break; } if (GrandpaFac == 2) //左 { if (parentFac == 1) // 左左 { singRotateLeft(tempGrandpa); } else // 左右 { doubleRotateLR(tempGrandpa); } rFlag = 1; } if (GrandpaFac == -2) //右 { if (parentFac == 1) // 右左 { singRotateLeft(tempGrandpa); } else // 右右 { singRotateRight(tempGrandpa); } rFlag = 1; } if (!rFlag) // 把可能出现问题的节点往上移动 { tempParent = tempGrandpa; parentFac = GrandpaFac; tempGrandpa = tempParent->parent; } } } }}
欢迎批评指正 !
- 平衡二叉树(AVL)(一)
- 平衡二叉树(AVL)
- 平衡二叉树(AVL)
- 平衡二叉树(AVL)
- 平衡二叉树之AVL树(一)
- 平衡二叉树(AVL树)
- 平衡二叉树(AVL树)
- 平衡二叉树(AVL树)
- 数据结构:AVL树(平衡二叉树)
- 平衡二叉树(AVL树)
- AVL树(平衡二叉树)
- 平衡二叉树(AVL树)
- 平衡二叉树(AVL树)
- 平衡二叉树(AVL树)
- 平衡二叉树(AVL树)
- 平衡二叉树(AVL树)
- 平衡二叉树(AVL树)
- 平衡二叉树(AVL树)
- pdf怎么转换成jpg图片格式
- hdu 5768 LUCKY 7(数论...)
- 一道面试题目//C++
- 修改ProgressBar的进度条颜色
- 嵌入式Linux学习笔记
- 平衡二叉树(AVL)(一)
- Android逆向分析案例——某点评APP登陆请求数据解密
- Codeforces Round #109 (Div. 1) C. Double Profiles
- (支付问题)面向对象
- Qt实现自定义按钮的三态效果
- RxJava漫谈-RxAndroid使用
- Chrome中的小彩蛋
- C#中Socket用法,多个聊天和单一聊天。
- 结构体struct 名称定义详解