java数据结构avl树_Java数据结构与算法(5):AVL树

AVL树是带有平衡条件的二叉查找树,它是每个节点的左子树和右子树的高度最多差1的二叉查找树。AVL树的节点定义如下:

class AVLNode {

T element; // 键值

int height; // 高度

AVLNode left;

AVLNode right;

AVLNode(T element) {

this(element, null, null);

}

AVLNode(T element, AVLNode left, AVLNode right) {

this.element = element;

this.height = 0;

this.left = left;

this.right = right;

}

}

根据AVL树的性质,当插入新的节点时,可能破坏平衡性质,因此需要对树进行旋转来满足平衡条件。AVL树的不平衡可以总结为4种情形:LL、RR、LR、RL,由于对称性,逻辑上可以认为两种。

单旋转

LL型

3aa2dc060ccc9da3d5815198e2c91c4d.png

如图,当子树X插入新节点后,节点k2不满足AVL的平衡条件。为了使树恢复平衡,我们可以抽象地将树看成是柔和的,抓住k1节点使劲摇动它,在重力的作用下k1变成了新的根,k2变成了k1的右儿子,X和Z分别是k1的左儿子和k2的右儿子。子树Y介于k1和k2之间的那些节点,可以将它作为k2的左儿子,这样一棵新的AVL树诞生了。k1的高度取决于k1左子树X的高度和k1右子树k2的高度,k2的高度取决于k2的左子树Y和k2的右子树Z的高度。

LL旋转方法:

private AVLNode leftLeftRotation(AVLNode k2) {

AVLNode k1 = k2.left;

k2.left = k1.right;

k1.right = k2;

k2.height = max(height(k2.left), height(k2.right)) + 1;

k1.height = max(height(k1.left), k2.height) + 1;

return k1;

}

RR型

2433d67a2973e01163ca0c28990dd247.png

理解了上面的LL型旋转就不难理解RR型的旋转了,根据对称性,RR型也只需要通过一次单旋转就可以完成。

private AVLNode rightRightRotation(AVLNode k1) {

AVLNode k2 = k1.right;

k1.right = k2.left;

k2.left = k1;

k1.height = max(height(k1.left), height(k1.right)) + 1;

k2.height = max(height(k2.right), k1.height) + 1;

return k2;

}

双旋转

LR型

f10328ca645b560de27b5897ee952ec2.png

对于上图第一棵树描述的情形,由于以k2为父节点的子树为太深,这时候如果以k1为根节点,经过一次旋转后它就变成了RL型,依然不符合AVL树的平衡条件,因此,我们先忽略掉k3和D,左子树是一棵以k1为根节点的RR型二叉树,首先进行一次RR旋转,接着这就是一棵LL型树了,再次进行一次LL旋转,AVL树就生成了。

LR型旋转方式:

private AVLNode leftRightRotation(AVLNode k3) {

k3.left = rightRightRotation(k3.left);

return leftLeftRotation(k3);

}

RL型

3ac4f7960fc2ff4439f38018ab3bc5a1.png

根据对称性,理解RL型旋转应该不是一件很难的事了。RL型旋转方式:

private AVLNode rightLeftRotation(AVLNode k1) {

k1.right = leftLeftRotation(k1.right);

return rightRightRotation(k1);

}

插入

向一棵AVL树中插入新的节点时,我们的做法与二叉树查找树的思想是一样的,不同的是AVL树在插入新的节点后需要再执行一次平衡操作,如果树高度不平衡,需要进行单旋转或双旋转。

private AVLNode insert(T x, AVLNode t) {

if (t == null) {

return new AVLNode<>(x, null, null);

}

int cmp = x.compareTo(t.element);

if (cmp < 0) {

t.left = insert(x, t.left);

} else if (cmp > 0) {

t.right = insert(x, t.right);

} else {

// 重复值不处理

}

return balance(t);

}

balance方法:

private static final int ALLOWED_IMBALANCE = 1;

private AVLNode balance(AVLNode t) {

if (t == null) {

return t;

}

// 左儿子的高度大于右儿子的高度

if (height(t.left) - height(t.right) > ALLOWED_IMBALANCE) {

if (height(t.left.left) >= height(t.left.right)) {

// LL型-左儿子的左儿子高度大于左儿子的右儿子高度

t = leftLeftRotation(t);

} else {

// LR型-左儿子的右儿子高度大于左儿子的左儿子高度

t = leftRightRotation(t);

}

} else if (height(t.right) - height(t.left) > ALLOWED_IMBALANCE) {

// 右儿子高度大于左儿子高度

if (height(t.right.right) >= height(t.right.left)) {

// RR型-右儿子的右儿子高度大于右儿子的左儿子高度

t = rightRightRotation(t);

} else {

// RL型-右儿子的左儿子高度大于右儿子的右儿子高度

t = rightLeftRotation(t);

}

}

t.height = Math.max(height(t.left), height(t.right)) + 1;

return t;

}

删除

理解了插入操作,我们不难了解删除操作,就是在二叉查找树的删除基础上,在最后添加平衡操作。

private AVLNode remove(T x, AVLNode t) {

if (t == null) {

return t;

}

int cmp = x.compareTo(t.element);

if (cmp < 0) {

t.left = remove(x, t.left);

} else if (cmp > 0) {

t.right = remove(x, t.right);

} else if (t.left != null && t.right != null) {

t.element = findMin(t.right).element;

t.right = remove(t.element, t.right);

} else {

t = (t.left != null) ? t.left : t.right;

}

return balance(t);

}

AVL树的完成编码:

class AVLTree> {

private AVLNode root;

private int height(AVLNode tree) {

if (tree != null) {

return tree.height;

}

return 0;

}

public int height() {

return root.height;

}

public AVLNode search(T element) {

return search(root, element);

}

private AVLNode search(AVLNode x, T element) {

if (x == null) {

return x;

}

int cmp = element.compareTo(x.element);

if (cmp < 0) {

return search(x.left, element);

} else if (cmp > 0) {

return search(x.right, element);

} else {

return x;

}

}

public AVLNode insert(T x) {

return insert(x, root);

}

private AVLNode insert(T x, AVLNode t) {

if (t == null) {

return new AVLNode<>(x, null, null);

}

int cmp = x.compareTo(t.element);

if (cmp < 0) {

t.left = insert(x, t.left);

} else if (cmp > 0) {

t.right = insert(x, t.right);

} else {

// 重复值不处理

}

return balance(t);

}

public AVLNode remove(T x) {

return remove(x, root);

}

private AVLNode remove(T x, AVLNode t) {

if (t == null) {

return t;

}

int cmp = x.compareTo(t.element);

if (cmp < 0) {

t.left = remove(x, t.left);

} else if (cmp > 0) {

t.right = remove(x, t.right);

} else if (t.left != null && t.right != null) {

t.element = findMin(t.right).element;

t.right = remove(t.element, t.right);

} else {

t = (t.left != null) ? t.left : t.right;

}

return balance(t);

}

public AVLNode findMax() {

return findMax(root);

}

private AVLNode findMax(AVLNode x) {

if (x == null) {

return x;

}

while (x.right != null) {

x = x.right;

}

return x;

}

public AVLNode findMin() {

return findMin(root);

}

private AVLNode findMin(AVLNode x) {

if (x == null) {

return x;

}

while (x.left != null) {

x = x.left;

}

return x;

}

private AVLNode leftLeftRotation(AVLNode k2) {

AVLNode k1 = k2.left;

k2.left = k1.right;

k1.right = k2;

k2.height = max(height(k2.left), height(k2.right)) + 1;

k1.height = max(height(k1.left), k2.height) + 1;

return k1;

}

private AVLNode rightRightRotation(AVLNode k1) {

AVLNode k2 = k1.right;

k1.right = k2.left;

k2.left = k1;

k1.height = max(height(k1.left), height(k1.right)) + 1;

k2.height = max(height(k2.right), k1.height) + 1;

return k2;

}

private AVLNode leftRightRotation(AVLNode k3) {

k3.left = rightRightRotation(k3.left);

return leftLeftRotation(k3);

}

private AVLNode rightLeftRotation(AVLNode k1) {

k1.right = leftLeftRotation(k1.right);

return rightRightRotation(k1);

}

private int max(int a, int b) {

return a > b ? a : b;

}

private static final int ALLOWED_IMBALANCE = 1;

private AVLNode balance(AVLNode t) {

if (t == null) {

return t;

}

if (height(t.left) - height(t.right) > ALLOWED_IMBALANCE) {

if (height(t.left.left) >= height(t.left.right)) {

// LL型

t = leftLeftRotation(t);

} else {

// LR型

t = leftRightRotation(t);

}

} else if (height(t.right) - height(t.left) > ALLOWED_IMBALANCE) {

if (height(t.right.right) >= height(t.right.left)) {

// RR型

t = rightRightRotation(t);

} else {

// RL型

t = rightLeftRotation(t);

}

}

t.height = Math.max(height(t.left), height(t.right)) + 1;

return t;

}

private static class AVLNode {

T element; // 键值

int height; // 高度

AVLNode left;

AVLNode right;

public AVLNode(T element, AVLNode left, AVLNode right) {

this.element = element;

this.height = 0;

this.left = left;

this.right = right;

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值