AVL 트리 개념
앞에서 학습 이진 검색 트리 와 이진 트리 탐색의 다양한 , 그러나 그것의 검색 효율 불안정 (비스듬한 나무)하지만, 더 균형 이진 트리를 사용합니다. 훨씬 더 안정적에 비해 찾을 수 있습니다. ( 받는 시작 주목 데이터 구조 칼럼 )
- AVL 트리입니다 평형 조건과 이진 검색 트리 . 이 조건은 균형을 이루어야한다
容易保持
. 그리고 그 깊이가 O (logN)임을 확인합니다. - [정보의 AVL 트리 높이 차이 (단
平衡因子
) 1보다 크지 및 하위 트리의 각 평형도 이진 트리이다. - 균형 이진 트리의 최소 개수를 들어,
n0=0
,n1=1
,nk=n(k-1)+n(k-2)+1
, (BI Feibo 수준의 추구 과정은 피보나치 수 있습니다!)
난이도 : AVL 트리 진 일종이다, 규칙이나 법률의 어떤 종류의 그것을 할 수 있도록하기 위해 너무 높지 않은 복잡성 의 경우 동적으로 균형 을?
언밸런스 개요
당신은 단순히 대략 위, 단일 노드 보면 四种
상황, 그 최종 결과는 비슷한있다. 그냥 : 변화에 위아래로. 이것은 여전히 왼쪽도 오른쪽에 적절한 변화를 떠났다 .
이것은 오직 바닥위한 것임을 먼저 파악한다 발생할 수 균형 :
그래서 불평형 네 위해 하단에 나타나는, 또한 불균형의 결과, 중간 노드에서 나타나는 헤드에 나타날 수있다. 그리고 우리는 불균형의 첫 지점, 연구 할 필요가 계속 해결 한 후 균형 전체 트리를 . 물론, 실제적인 솔루션을 확실히 나타납니다 递归
문제를 해결하기 위해 아이디어를.
# 四种平衡旋转方式
RR平衡旋转(左单旋转)
出现这种情况的原因是节点的右侧的右侧较深这时候不平衡节
点需要左旋
。再细看过程。
- 再左旋的过程中,
root(oldroot)
节点下沉,中间节点(newroot)
上浮.而其中中间节点(newroot)
的右侧依然不变。 - 它上浮左侧所以需要指向
根节点(oldroot)
(毕竟一棵树)。但是这样newroot
原来左侧节点H
空缺。而我们需要仍然让整个树完整并且满足二叉排序树的规则。 - 而刚好本来oldroot右侧指向newroot变成oldroot被newroot左侧指向。所以
oldroot右侧空缺
,刚好这个位置满足
在oldroot的右侧。在newroot的左侧。.所以我们将H插入在这个位置。 - 其中H可能为
NULL
。不过不影响操作!
而左旋的代码可以表示为:
private node getRRbanlance(node oldroot) {//右右深,需要左旋
// TODO Auto-generated method stub
node newroot=oldroot.right;
oldroot.right=newroot.left;
newroot.left=oldroot;
oldroot.height=Math.max(getHeight(oldroot.left),getHeight(oldroot.right))+1;
newroot.height=Math.max(getHeight(newroot.left),getHeight(newroot.right))+1;//原来的root的高度需要从新计算
return newroot;
}
LL平衡旋转(右单旋转)
而右旋和左旋相反,但是思路相同,根据上述进行替换即可!
代码:
private node getLLbanlance(node oldroot) {//LL小,需要右旋转
// TODO Auto-generated method stub
node newroot=oldroot.left;
oldroot.left=newroot.right;
newroot.right=oldroot;
oldroot.height=Math.max(getHeight(oldroot.left),getHeight(oldroot.right))+1;
newroot.height=Math.max(getHeight(newroot.left),getHeight(newroot.right))+1;//原来的root的高度需要从新金酸
return newroot;
}
RL平衡旋转(先右后左双旋转)
产生不平衡的条件原因是:
root节点右侧左侧节点的深度高些
,使得与左侧的差大于1
.这个与我们前面看到的左旋右旋不同的是因为它的结构不能直接变一下就可以完成。- 因为对于右左结构,中间的最大,两侧的最小。但是下面的比上面大(
下面在上面右侧
)所以如果平衡的话,那么右左的R.L
应该在中间,而R
应该在右侧
。原来的root在左侧。 - 所以节点的变化浮动比较大,而且需要妥善处理各个子节点的移动使其满足二叉排序树的性质!
- 期间考虑树高度变化即可!
这种双旋转其实也很简单。不要被外表唬住。基于前面的单旋转,双旋转有两种
具体逻辑思路
。
思路1:两次旋转RR,LL
根据上图所圈的,先对底部使得底部的大小关系变化,使其在满足二叉平衡树的条件下还满足RR结构的二叉树。所以只需要对右节点R先进行右旋
,再对ROOT进行左旋即可。
思路2:直接分析
根据初始和结果的状态,然后分析各个节点变化顺序。手动操作这些节点即可!
- 首先根据
ROOT,R,R.L
三个节点变化。R.L肯定要在最顶层。左右分别指向ROOT和R。那么这其中R.left,ROOT.right
发生变化(原来分别是R,L和R)暂时为空。而刚好根据左右大小关系可以补上R.L的左右节点
。 - 这样思考整棵树也可以完成平衡,但是要考虑树的高度变化。
代码为:(注释部分为方案1)
private node getRLbanlance(node oldroot) {//右左深
// node newroot=oldroot.right.left;
// oldroot.right.left=newroot.right;
// newroot.right=oldroot.right;
// oldroot.right=newroot.left;
// newroot.left=oldroot;
// oldroot.height=Math.max(getHeight(oldroot.left),getHeight(oldroot.right))+1;
// newroot.right.height=Math.max(getHeight(newroot.right.left),getHeight(newroot.right.right))+1;
// newroot.height=Math.max(getHeight(oldroot.left),getHeight(newroot.right))+1;//原来的root的高度需要从新金酸
oldroot.right =getLLbanlance(oldroot.right);
oldroot.height=Math.max(getHeight(oldroot.left), getHeight(oldroot.right))+1;
return getRRbanlance(oldroot);
}
LR平衡旋转(先左后右单旋转)
根据上述RL修改即可
private node getLRbanlance(node oldroot) {
oldroot.left =getRRbanlance(oldroot.left);
oldroot.height=Math.max(getHeight(oldroot.left), getHeight(oldroot.right))+1;
return getLLbanlance(oldroot);
}
java代码实现
- 首先对于节点多个
height
属性。用于计算高度(平衡因子) 插入是递归插入。递归一个来回的过程,去的过程进行插入。回的过程进行高度更新。和检查是否平衡。不要写全局递归计算高度,效率太低下。事实上高度变化只和插入和平衡有关,仔细考虑即不会有疏漏!
总结
测试情况:
- AVL의 이해는 물론, AVL의 저자가 자신의를 작성, 시간이 걸리는
可能有些疏漏
문제도하시기 바랍니다 경우一起探讨
! - 물론,뿐만 아니라, AVL뿐만 아니라 삽입 할
删除
다른 작업을, (원리는 비슷합니다. 당신이 균형을 제거한 후) 함께 공부할 수 있습니다 관심이 있습니다. - 소스 코드가 필요한 경우도 대중의 관심을 저자 번호를 요구 : 없음 공공보기 특집 기사를!
경우
后端、爬虫、数据结构算法
섹스 공공 교환 수의 내 개인적인 관심을 다른 감각 환영주의 :bigsai
(응답 데이터 구조, 파충류, 자바 및 기타 정보가 잘 준비!)