百科定义
平衡二叉树(Balanced Binary Tree)具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
平衡因子
二叉树上节点的左子树深度减去右子树深度的值称为平衡因子BF(Balance Factor)
平衡二叉树的实现
调整平衡的基本思想:
当在二叉排序树中插入一个节点时,首先检查是否因插入而破坏了平衡,若破坏,则找出其中的最小不平衡二叉树,在保持二叉排序树特性的情况下,调整最小不平衡子树中节点之间的关系,以达到新的平衡。
所谓最小不平衡子树,指离插入节点最近且以平衡因子的绝对值大于1的节点作为根的子树。
实现平衡的方法:
. 左旋
上图中,最小不平衡子树为结点3下面的树,结点3 的平衡因子BF为-2。
平衡方法为:以结点3进行左旋,旋转结果为图8。旋转后变为平衡二叉树
旋转方法
如上图,我们对X进行左旋,为了方便表达,做如下初始定义,保存左旋前节点的数据:
- X为node
- X的父结点为nodeP
- X的左结点为nodeL
- X的右节点为NodeR
- X的右子树的左节点为nodeRL
- X的右子树的右节点位nodeRR
变换步骤:
-
- node的右节点改为nodeRL,nodeRL的父结点改为node
-
- 判断node属于nodeP的左孩子还是右孩子,nodeP指向nodeR,nodeR的父亲结点改为nodeP
-
- nodeR指向node,node的父结点变为nodeR
public void left_rotate(Node x) {
if (x != null) {
Node y = x.right;
// step 1
x.right = y.left;
if (y.left != null) {
y.left.parent = x;
}
// step2
y.parent = x.parent;
if (x.parent == null) {
root = y;
} else {
if (x.parent.left == x) {
x.parent.left = y;
} else if(x.parent.right == x){
x.parent.right = y;
}
}
//step 3
y.left = x;
x.parent = y;
}
}
. 右旋
上图中,节点3的平衡因子为2,左边的多于右边,需要进行右旋,把内容分配到右边一部分。
同左旋,定义保存右旋前一些使用到节点的数据
- Y 保存为node
- Y的父结点保存为nodeP
- Y的左节点保存为nodeL
- Y的右节点保存为nodeR
- Y的左节点的右孩子保存为nodeLR
- Y的左节点的左孩子保存为nodeLL
步骤:
-
- node的右孩子变为nodeLR,nodeLR父结点变为node
-
- 判断node属于nodeP的左孩子还是右孩子,nodeP指向nodeL,nodeL的父结点改为nodeP
-
- nodeL的右孩子变为node,node的父结点变为nodeL
public void right_rotate(Node y) {
if (y != null) {
Node yl = y.left;
//step1
y.left= yl.right;
if (yl.right != null) {
yl.right.parent = y;
}
// step2
yl.parent = y.parent;
if (y.parent == null) {
root = yl;
} else {
if (y.parent.left == y) {
y.parent.left = yl;
} else if (y.parent.right == y) {
y.parent.right = yl;
}
}
// step3
yl.right = y;
y.parent = yl;
}
}
插入结点时候,导致平衡树失衡的情况分析,处理步骤
结点t的不平衡是因为左子树过深
/**
* 左平衡操作,即结点t的不平衡是因为左子树过深
*
* 1、如果新的结点插入到t的左孩子的左子树中,则直接进行右旋操作即可
* t tl
* / \ 右旋操作 / \
* tl tr -------------> tll t
* / \ / \ / \
* tll tlr lcll lclr tlr tr
* / \
* lcll lclr
*
* 2、如果新的结点插入到t的左孩子的右子树中,则需要进行分情况讨论
*
* 情况a:当t的左孩子的右子树根节点的balance = RIGHT_HIGH
* t t tlr
* / \ / \ / \
* tl 6 左旋 tlr 6 右旋 tl t
* / \ -------> / \ --------> / / \
* 3 tlr tl 5 3 5 6
* \ /
* 5 3
* 情况b:当p的左孩子的右子树根节点的balance = LEFT_HIGH
*
* t t tlr
* / \ / \ / \
* tl 6 左旋 tlr 6 右旋 tl t
* / \ -------> / --------> / \ \
* 3 tlr tl 3 5 6
* / / \
* 5 3 5
*
* 情况c:当p的左孩子的右子树根节点的balance = EQUAL_HIGH
*
* t t tlr
* / \ / \ / \
* tl 7 左旋 tlr 7 右旋 tl t
* / \ -------> / \ --------> / \ / \
* 3 tlr tl 6 3 5 6 7
* / \ / \
* 5 6 3 5
* */
结点t的不平衡是因为左子树过深调整代码
private static final int LH = 1;
private static final int RH = -1;
private static final int EH = 0;
private void leftBalance(AVL.Node t) {
Node tl = t.left;
switch (tl.balance) {
case LH: // t 的左子树的左边有问题,直接右旋
right_rotate(t);
tl.balance = EH;
t.balance = EH;
break;
case RH:
Node tlr = tl.right;
switch (tlr.balance) {
case RH:
t.balance = EH;
tlr.balance = EH;
tl.balance = LH;
break;
case LH:
t.balance = RH;
tl.balance =EH;
tlr.balance = EH;
break;
case EH:
t.balance = EH;
tl.balance = EH;
tlr.balance =EH;
break;
//统一旋转
default:
break;
}
left_rotate(t.left);
right_rotate(t);
break;
default:
break;
}
}
结点t的不平衡是因为右子树过深
/**
* 右平衡操作,即结点t的不平衡是因为右子树过深
*
* 1、如果新的结点插入到t的右孩子的右子树中,则直接进行左旋操作即可
*
* t tr
* / \ / \
* l tr 左旋操作 t rr
* / \ -----------> / \ / \
* rl rr l rl rrl rrr
* / \
* rrl rrr
* 2、如果新的结点插入到p的右孩子的左子树中,则需要进行分情况讨论
* 情况a:当p的右孩子的左子树根节点的balance = LEFT_HIGH
*
* t t trl
* / \ / \ / \
* 2 tr 右旋 2 trl 左旋 t tr
* / \ -------> / \ -------> / \ \
* trl 5 6 tr 2 6 5
* / \
* 6 5
* 情况b:当p的右孩子的左子树根节点的balance = RIGHT_HIGH
*
* t t trl
* / \ / \ / \
* 2 tr 右旋 2 trl 左旋 t tr
* / \ -------> \ -------> / / \
* trl 5 tr 2 6 5
* \ / \
* 6 6 5
* 情况C:当p的右孩子的左子树根节点的balance = EQUAL_HIGH
* t t trl
* / \ / \ / \
* 2 tr 右旋 2 trl 左旋 t tr
* / \ -------> / \ -------> / \ / \
* trl 5 6 tr 2 6 7 5
* / \ / \
* 6 7 7 5
* */
结点t的不平衡是因为右子树过深调整代码
private static final int LH = 1;
private static final int RH = -1;
private static final int EH = 0;
private void rightBalance(AVL.Node t) {
Node tr = t.right;
switch (tr.balance) {
case RH:
left_rotate(t);
t.balance = EH;
tr.balance = EH;
break;
case LH:
Node trl = tr.left;
switch (trl.balance) {
case LH:
t.balance = EH;
tr.balance = RH;
break;
case RH:
t.balance = LH;
tr.balance = EH;
break;
case EH:
t.balance = EH;
tr.balance = EH;
break;
}
trl.balance = EH;
right_rotate(t.right);
left_rotate(t);
break;
default:
break;
}
}
插入操作
public boolean inserElement(E element) {
Node t = root;
if (t == null) {
root = new Node(element, null);
size = 1;
root.balance = 0;
return true;
} else {
int cmp = 0;
Node parent;
Comparable super E> e = (Comparable super E>)element;
do {
parent = t;
cmp = e.compareTo(t.element);
if (cmp < 0) {
t= t.left;
} else if (cmp > 0) {
t= t.right;
} else {
return false;
}
} while (t != null);
Node child = new Node(element, parent);
if (cmp < 0) {
parent.left = child;
} else {
parent.right = child;
}
//节点已经插入,
// 检查平衡,回溯查找
while (parent != null) {
cmp = e.compareTo(parent.element);
//元素在左边插入
if (cmp < 0) {
parent.balance++;
} else{ //元素在右边插入
parent.balance --;
}
if (parent.balance == 0) {
break;
}
if (Math.abs(parent.balance) == 2) {
//出现平衡问题
fixAfterInsertion(parent);
break;
} else {
parent = parent.parent;
}
}
size++;
return true;
}
}
private void fixAfterInsertion(AVL.Node parent) {
if (parent.balance == 2) {
leftBalance(parent);
}
if (parent.balance == -2) {
rightBalance(parent);
}
}
全部代码
import java.util.LinkedList;
public class AVL> {
private Node root;
private int size = 0;
private static final int LH = 1;
private static final int RH = -1;
private static final int EH = 0;
public void midOrderDisplay(Node root) {
if (root == null) {
return;
} else {
midOrderDisplay(root.left);
System.out.println("midOrder: " + root.element);
midOrderDisplay(root.right);
}
}
/**
* node insert,check balance and keep balance
* @author LK
*
* @param
*/
public boolean inserElement(E element) {
Node t = root;
if (t == null) {
root = new Node(element, null);
size = 1;
root.balance = 0;
return true;
} else {
int cmp = 0;
Node parent;
Comparable super E> e = (Comparable super E>)element;
do {
parent = t;
cmp = e.compareTo(t.element);
if (cmp < 0) {
t= t.left;
} else if (cmp > 0) {
t= t.right;
} else {
return false;
}
} while (t != null);
Node child = new Node(element, parent);
if (cmp < 0) {
parent.left = child;
} else {
parent.right = child;
}
//节点已经插入,
// 检查平衡,回溯查找
while (parent != null) {
cmp = e.compareTo(parent.element);
//元素在左边插入
if (cmp < 0) {
parent.balance++;
} else{ //元素在右边插入
parent.balance --;
}
if (parent.balance == 0) {
break;
}
if (Math.abs(parent.balance) == 2) {
//出现平衡问题
fixAfterInsertion(parent);
break;
} else {
parent = parent.parent;
}
}
size++;
return true;
}
}
private void fixAfterInsertion(AVL.Node parent) {
if (parent.balance == 2) {
leftBalance(parent);
}
if (parent.balance == -2) {
rightBalance(parent);
}
}
private void rightBalance(AVL.Node t) {
Node tr = t.right;
switch (tr.balance) {
case RH:
left_rotate(t);
t.balance = EH;
tr.balance = EH;
break;
case LH:
Node trl = tr.left;
switch (trl.balance) {
case LH:
t.balance = EH;
tr.balance = RH;
break;
case RH:
t.balance = LH;
tr.balance = EH;
break;
case EH:
t.balance = EH;
tr.balance = EH;
break;
}
trl.balance = EH;
right_rotate(t.right);
left_rotate(t);
break;
default:
break;
}
}
private void left_rotate(AVL.Node t) {
if (t != null) {
Node tr = t.right;
t.right = tr.left;
if (tr.left != null) {
tr.left.parent = t;
}
tr.parent = t.parent;
if (t.parent == null) {
root = tr;
} else {
if (t.parent.left == t) {
t.parent.left = tr;
} else if (t.parent.right == t) {
t.parent.right = tr;
}
}
tr.left = t;
t.parent = tr;
}
}
private void right_rotate(AVL.Node t) {
if (t != null) {
Node tl = t.left;
t.left =tl.right;
if (tl.right != null) {
tl.right.parent = t;
}
tl.parent = t.parent;
if (t.parent == null) {
root = tl;
} else {
if (t.parent.left == t) {
t.parent.left = tl;
} else if (t.parent.right == t) {
t.parent.right = tl;
}
}
tl.right = t;
t.parent = tl;
}
}
public Node searchNode(E element) {
if (root == null) {
return null;
} else {
Node cur = root;
while(cur != null) {
if (element.compareTo(cur.element) > 0) {
cur = cur.right;
} else if (element.compareTo(cur.element) < 0) {
cur = cur.left;
} else {
return cur;
}
}
}
return null;
}
private void leftBalance(AVL.Node t) {
Node tl = t.left;
switch (tl.balance) {
case LH: // t 的左子树的左边有问题,直接右旋
right_rotate(t);
tl.balance = EH;
t.balance = EH;
break;
case RH:
Node tlr = tl.right;
switch (tlr.balance) {
case RH:
t.balance = EH;
tlr.balance = EH;
tl.balance = LH;
break;
case LH:
t.balance = RH;
tl.balance =EH;
tlr.balance = EH;
break;
case EH:
t.balance = EH;
tl.balance = EH;
tlr.balance =EH;
break;
//统一旋转
default:
break;
}
left_rotate(t.left);
right_rotate(t);
break;
default:
break;
}
}
class NodeBF {
int level;
Node node;
public NodeBF(Node node, int lev) {
this.node = node;
level = lev;
}
}
class Node>{
E element; // data
int balance = 0; // balance value
Node left;
Node right;
Node parent;
public Node(E element, Node parent) {
this.element = element;
this.parent = parent;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return element + "BF: " + balance;
}
public E getElement() {
return element;
}
public void setElement(E element) {
this.element = element;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
public Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
public Node getParent() {
return parent;
}
public void setParent(Node parent) {
this.parent = parent;
}
}
public Node getRoot() {
return root;
}
public void levelDisplay(Node root) {
LinkedList list = new LinkedList<>();
NodeBF nodeBF = new NodeBF(root, 0);
list.offer(nodeBF);
while (!list.isEmpty()) {
NodeBF node = list.pop();
System.out.println(node.node.element + " level: " + node.level);
if (node.node.left != null) {
NodeBF nodel = new NodeBF(node.node.left, node.level + 1);
list.offer(nodel);
}
if (node.node.right != null) {
NodeBF noder = new NodeBF(node.node.right, node.level + 1);
list.offer(noder);
}
}
}
public static void main(String[] args) {
// Integer[] nums = {5, 8, 2, 0, 1, -2, -9, 100};
Integer[] nums = {5, 8, 2, 0, 1, -2};
AVL vAvlTree = new AVL();
for (int i = 0; i < nums.length; i++) {
vAvlTree.inserElement(nums[i]);
}
// vAvlTree.midOrderDisplay(vAvlTree.root);
vAvlTree.levelDisplay(vAvlTree.root);
System.out.println(vAvlTree.root.element);
}
}