平衡二叉树(AVL树)
1、问题引入
给你一个数列{1,2,3,4,5,6},要求创建一颗二叉排序树(BST), 并分析问题所在.
左子树全部为空,从形式上看,更像一个单链表.插入速度没有影响查询速度明显降低(因为需要依次比较), 不能发挥 BST的优势,因为每次还需要比较左子树,其查询速度比单链表还慢解决方案-平衡二叉树(AVL)
2、基本介绍
平衡二叉树也叫平衡 二叉搜索树(Self-balancingbinary search tree)又被称为 AVL 树,可以保证查询效率较高。具有以下特点:它是一 一 棵空树或 它的左右两个子树的==高度差的绝对值不超过 1==,并且 左右两个子树都是一棵 平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等。举例说明, 看看下面哪些 AVL 树, 为什么?
3、单旋转(left)
3.1、问题分析
要求: 给你一个数列,创建出对应的平衡二叉树.数列 {4,3,6,5,7,8}
3.2、代码实现
private void leftRotate(){
Node newNode
= new Node(value
);
newNode
.left
= left
;
newNode
.right
= right
.left
;
value
= right
.value
;
right
= right
.right
;
left
= newNode
;
}
4、右旋转(right)
4.1、问题分析
要求: 给你一个数列,创建出对应的平衡二叉树.数列 {10,12, 8, 9, 7, 6}
4.2、代码实现
private void rightRotate(){
Node newNode
= new Node(value
);
newNode
.right
= right
;
newNode
.left
= left
.right
;
value
= left
.value
;
left
= left
.left
;
right
= newNode
;
}
5、双旋转
5.1、问题分析
前面的两个数列,进行单旋转(即一次旋转)就可以将非平衡二叉树转成平衡二叉树,但是在某些情况下,单旋转 不能完成平衡二叉树的转换。比如数列 int[] arr = { 10, 11, 7, 6, 8, 9 }; 运行原来的代码可以看到,并没有转成 AVL 树. int[] arr = {2,1,6,5,7,3}; // 运行原来的代码可以看到,并没有转成 AVL 树
解决思路分析
当符合右旋转的条件时如果它的左子树的右子树高度大于它的左子树的左子树的高度先对当前这个结点的左节点进行左旋转在对当前结点进行右旋转的操作即可
如果是在左旋转的条件下,把右全换成左即可
5.2、代码实现(完整)
public class AVLTreeDemo {
public static void main(String
[] args
) {
int[] arr
= { 10, 11,7,6,8,9};
AVLTree avlTree
= new AVLTree();
for (int i
= 0; i
< arr
.length
; i
++) {
avlTree
.add(new Node(arr
[i
]));
}
System
.out
.println("中序遍历");
avlTree
.infixOrder();
System
.out
.println("在没有平衡处理前~~");
System
.out
.println("树的高度=" + avlTree
.getRoot().height());
System
.out
.println("树的左子树的高度=" + avlTree
.getRoot().leftHeight());
System
.out
.println("树的右子树的高度=" + avlTree
.getRoot().rightHeight());
System
.out
.println("当前根节点=" + avlTree
.getRoot());
System
.out
.println("根节点的左子节点=" + avlTree
.getRoot().right
.right
);
}
}
class AVLTree{
private Node root
;
public Node
getRoot(){
return root
;
}
public Node
search(int value
){
if (root
== null
){
return null
;
}else {
return root
.search(value
);
}
}
public Node
searchParent(int value
){
if (root
== null
){
return null
;
}else {
return root
.searchParent(value
);
}
}
public int delRightTreeMin(Node node
){
Node target
= node
;
while (target
.left
!= null
){
target
= target
.left
;
}
delNode(target
.value
);
return target
.value
;
}
public void delNode(int value
){
if (root
== null
){
return;
}else {
Node targetNode
= search(value
);
if (targetNode
== null
){
return;
}
if (root
.left
== null
&& root
.right
== null
){
root
= null
;
return;
}
Node parent
= searchParent(value
);
if (targetNode
.left
== null
&& targetNode
.right
== null
){
if ( parent
.left
!= null
&& targetNode
.value
== parent
.left
.value
){
parent
.left
= null
;
}else if (parent
.right
!= null
&& parent
.right
.value
== targetNode
.value
){
parent
.right
= null
;
}
}else if (targetNode
.left
!= null
&& targetNode
.right
!= null
){
int minVal
= delRightTreeMin(targetNode
.right
);
targetNode
.value
= minVal
;
}else {
if (targetNode
.left
!= null
){
if (parent
!= null
){
if (parent
.left
.value
== value
){
parent
.left
= targetNode
.left
;
}else {
parent
.right
= targetNode
.left
;
}
}else {
root
= targetNode
.left
;
}
}else {
if (parent
!= null
){
if (parent
.left
.value
== value
){
parent
.left
= targetNode
.right
;
}else {
parent
.right
= targetNode
.right
;
}
}else {
root
= targetNode
.right
;
}
}
}
}
}
public void add(Node node
){
if (root
== null
){
root
= node
;
}else {
root
.add(node
);
}
}
public void infixOrder(){
if (root
!= null
){
root
.infixOrder();
}else {
System
.out
.println("二叉树为空, 无法进行中序遍历~~");
}
}
}
class Node{
int value
;
Node left
;
Node right
;
public Node(int value
) {
this.value
= value
;
}
public int leftHeight(){
if (left
== null
){
return 0;
}
return left
.height();
}
public int rightHeight(){
if (right
== null
){
return 0;
}
return right
.height();
}
public int height(){
return Math
.max(left
== null
? 0 : leftHeight(),right
== null
? 0 : rightHeight()) + 1;
}
private void leftRotate(){
Node newNode
= new Node(value
);
newNode
.left
= left
;
newNode
.right
= right
.left
;
value
= right
.value
;
right
= right
.right
;
left
= newNode
;
}
private void rightRotate(){
Node newNode
= new Node(value
);
newNode
.right
= right
;
newNode
.left
= left
.right
;
value
= left
.value
;
left
= left
.left
;
right
= newNode
;
}
@Override
public String
toString() {
return "Node{" +
"value=" + value
+
'}';
}
public void add(Node node
){
if (node
== null
){
return;
}
if (node
.value
< this.value
){
if (this.left
== null
){
this.left
= node
;
}else {
this.left
.add(node
);
}
}else {
if (this.right
== null
){
this.right
= node
;
}else {
this.right
.add(node
);
}
}
if (rightHeight() - leftHeight() > 1){
if (right
!= null
&& right
.leftHeight() > right
.rightHeight()){
right
.rightRotate();
leftRotate();
}else {
leftRotate();
}
return;
}
if (leftHeight() - rightHeight() > 1){
if (left
!= null
&& left
.rightHeight() > left
.leftHeight()){
left
.leftRotate();
rightRotate();
}else {
rightRotate();
}
}
}
public void infixOrder(){
if (this.left
!= null
){
this.left
.infixOrder();
}
System
.out
.println(this);
if (this.right
!= null
){
this.right
.infixOrder();
}
}
public Node
search(int value
){
if (value
== this.value
){
return this;
}else if (value
< this.value
){
if (this.left
== null
){
return null
;
}
return this.left
.search(value
);
}else {
if (this.right
== null
){
return null
;
}
return this.right
.search(value
);
}
}
public Node
searchParent(int value
){
if ((this.left
!= null
&& value
== this.left
.value
)||(this.right
!= null
&& value
== this.right
.value
)){
return this;
}else if (this.left
!= null
&& value
< this.value
){
return this.left
.searchParent(value
);
}else if (this.right
!= null
&& value
>= this.value
){
return this.right
.searchParent(value
);
}else {
return null
;
}
}
}
运行结果:
中序遍历 Node{value=6} Node{value=7} Node{value=8} Node{value=9} Node{value=10} Node{value=11} 在没有平衡处理前~~ 树的高度=3 树的左子树的高度=2 树的右子树的高度=2 当前根节点=Node{value=8} 根节点的左子节点=Node{value=11}