您的位置:首页 > 其它

平衡二叉树(AVL树)

2013-11-28 12:46 525 查看
平衡二叉树的接口

package tree;

/**
* 平衡二叉树的操作
*
* @author liangguojun
*
* @param <T>
*            数据类型,该数据类型必须实现Comparable接口
*/
public interface SortAVLTree<T extends Comparable<T>> {
public static final int ASC_VALUE = 1;
public static final int DESC_VALUE = 0;

/**
* 判断平衡二叉树是否为空
*
* @return 平衡二叉树为空则返回true,否则返回false
*/
public boolean isEmpty();

/**
* 求平衡二叉树的长度
*
* @return 返回平衡二叉树的长度
*/
public int getLength();

/**
* 插入数据,插入数据后自动调整平衡二叉树
*
* @param data
*            数据元素
* @return 成功插入则返回true,否则返回false
*/
public boolean insert(T data);

/**
* 删除数据元素节点
*
* @param data
*            将要删除的数据元素节点
* @return 成功删除则返回true,否则返回false
*/
public boolean delete(T data);

/**
* 根据传入的参数,按升序或者降序遍历平衡二叉树
*
* @param VALUE
*            排序的控制参数
*/
public void view(int VALUE);

/**
* 将数据元素move的数据改为data
*
* @param data
*            替换的数据元素
* @param move
*            被替换的数据元素
* @return 成功替换则返回true,否则返回false
*/
public boolean update(T data, T move);

/**
* 返回平衡二叉树的深度
*
* @return 返回平衡二叉树的深度
*/
public int getDept();
}


平衡二叉树的节点类:

package tree;

/**
* 平衡二叉树的节点类
*
* @author liangguojun
*
* @param <T>
*            数据类型
*/
public class BirTreeNode<T> {
private T data;
private int bf;
private BirTreeNode<T> lchild, rchild;

public BirTreeNode(T data, int bf, BirTreeNode<T> lchild,
BirTreeNode<T> rchild) {
this.setData(data);
this.setBf(bf);
this.setLchild(lchild);
this.setRchild(rchild);
}

public BirTreeNode(T data) {
this(data, 0, null, null);
}

public BirTreeNode(T data, BirTreeNode<T> lchild, BirTreeNode<T> rchild) {
this(data, 0, lchild, rchild);
}

public T getData() {
return data;
}

public void setData(T data) {
this.data = data;
}

public int getBf() {
return bf;
}

public void setBf(int bf) {
this.bf = bf;
}

public BirTreeNode<T> getLchild() {
return lchild;
}

public void setLchild(BirTreeNode<T> lchild) {
this.lchild = lchild;
}

public BirTreeNode<T> getRchild() {
return rchild;
}

public void setRchild(BirTreeNode<T> rchild) {
this.rchild = rchild;
}

public String toString() {
return data.toString();
}
}


平衡二叉树的实现,参考《大话数据结构》的实现方法

package tree;
/**
* 平衡二叉树的实现,参考《大话数据结构》的实现方法
* @author liangguojun
*
* @param <T>
*/
public class AVLSortTree<T extends Comparable<T>> implements SortAVLTree<T> {

// 用于控制插入一个节点后判断树是否长高了。
private boolean taller = false;
// 用于控制删除数据元素是树是否变矮了。
private boolean shorter = false;
// 根节点
private BirTreeNode<T> root;
// 左高
public static final int LH = 1;
// 等高
public static final int EH = 0;
// 右高
public static final int RH = -1;

public AVLSortTree() {
root = null;
}

// 返回根节点
public BirTreeNode<T> getRoot() {
return root;
}

@Override
public boolean isEmpty() {
if (root == null) {
return true;
}
return false;
}

/**
* 求子树cur的长度
*
* @param cur
*            子树的根结点cur
* @return 返回子树的长度
*/
private int getLength(BirTreeNode<T> cur) {
if (cur != null) {
int lc = 0;
int rc = 0;
if (cur.getLchild() != null)
lc = getLength(cur.getLchild()) + 1;
if (cur.getRchild() != null)
rc = getLength(cur.getRchild()) + 1;
return lc + rc;
}
return 0;
}

@Override
public int getLength() {
if (root != null)
return getLength(root) + 1;
return 0;
}

/**
* 右旋转的方法,当子树右旋转时,双亲不为空,则应该修改双亲的节点
*
* @param cur
*            需要旋转的子树根节点
* @param parent
*            子树的双亲节点
*/
private void rightRotate(BirTreeNode<T> cur, BirTreeNode<T> parent) {
if (cur != null && cur.getLchild() != null) {
// 旋转操作
BirTreeNode<T> L = cur.getLchild();
cur.setLchild(L.getRchild());
L.setRchild(cur);
// 假如是根节点的话,则修改根节点
if (parent == null) {

root = L;

} else {

// 假如cur的双亲parent的左孩子是cur,则修改左孩子,否则修改右孩子
if (parent != null && parent.getLchild() == cur) {
parent.setLchild(L);
} else if (parent != null && parent.getRchild() == cur) {
parent.setRchild(L);
}
}
}
}

/**
* 左旋转的方法
*
* @param cur
*            需要左旋转的子树的根节点
* @param parent
*            需要旋转子树的双亲节点
*/
private void leftRotate(BirTreeNode<T> cur, BirTreeNode<T> parent) {
if (cur != null && cur.getRchild() != null) {
BirTreeNode<T> R = cur.getRchild();
cur.setRchild(R.getLchild());
R.setLchild(cur);
// 假如是根节点的话,则修改根节点
if (parent == null) {
root = R;
}
if (parent != null && parent.getLchild() == cur) {
parent.setLchild(R);
} else if (parent != null && parent.getRchild() == cur) {
parent.setRchild(R);
}

}
}

/**
* 对cur为根节点的二叉树做左旋转处理,方法结束后,根节点改变,如果cur右双亲节点,则应该修改双亲节点的孩子节点
*
* @param cur
*            二叉树的根节点
* @param parent
*            cur二叉树的双亲节点
*/
private void leftBalance(BirTreeNode<T> cur, BirTreeNode<T> parent) {
if (cur.getLchild() != null) {
BirTreeNode<T> L = cur.getLchild();
BirTreeNode<T> Lr;
switch (L.getBf()) {
case LH: // 根节点左边高,左子树也是左边高,所以直接一次右旋转即可
cur.setBf(EH);
L.setBf(EH);
rightRotate(cur, parent);
break;

case RH: // 根节点左边高,而左子树是右边树高,所以要双旋转,使要旋转的树的符号一样
// 先对左子树左旋转,使左子树变成左边高 ,才能进行右旋转
Lr = L.getRchild();
// 修改平衡标志
switch (Lr.getBf()) {
case LH:
cur.setBf(RH);
L.setBf(EH);
break;
case EH:
cur.setBf(EH);
L.setBf(EH);
break;
case RH:
cur.setBf(EH);
L.setBf(LH);
break;
}
Lr.setBf(EH);
// 先对最小不平衡树左旋
leftRotate(L, cur);
// 对整棵树进行右旋
rightRotate(cur, parent);
}
}
}

/**
* 对cur为根节点的二叉树做右旋转处理,方法结束后,根节点改变,如果cur右双亲节点,则应该修改双亲节点的孩子节点
*
* @param cur
*            需要进行右平衡处理的子树的根节点
* @param parent
*            cur的双亲节点
*/
private void rightBalance(BirTreeNode<T> cur, BirTreeNode<T> parent) {
if (cur.getRchild() != null) {
BirTreeNode<T> R = cur.getRchild();
BirTreeNode<T> Rl;
switch (R.getBf()) {
// 旋转时的子树根节点右边高
case RH:
cur.setBf(EH);
R.setBf(EH);
leftRotate(cur, parent);
break;
// 旋转时的子树的根节点左边高,跟根节点的符号不一样,要进行双旋转处理
case LH:
Rl = R.getLchild();
switch (Rl.getBf()) {
case LH:
R.setBf(RH);
cur.setBf(EH);
break;
case EH:
R.setBf(EH);
cur.setBf(EH);
break;
case RH:
cur.setBf(LH);
R.setBf(EH);
break;
}
Rl.setBf(EH);
rightRotate(R, cur);
leftRotate(cur, parent);

}
}
}

/**
* 插入节点的方法
*
* @param cur
*            被插入的节点
* @param parent
*            插入节点的双亲
* @param data
*            插入的数据元素
* @return 成功插入则返回true,否则返回false
*/
private boolean insert(BirTreeNode<T> cur, BirTreeNode<T> parent, T data) {

if (data != null) {
if (cur == null) {
cur = new BirTreeNode<T>(data);
// 插入节点作为双亲节点的左孩子还是右孩子
if (parent.getData().compareTo(cur.getData()) > 0) {
parent.setLchild(cur);
}
if (parent.getData().compareTo(cur.getData()) < 0) {
parent.setRchild(cur);
}
taller = true;
} else {
if (data.compareTo(cur.getData()) == 0) {
taller = false;
return false;
}
if (data.compareTo(cur.getData()) < 0) {
// 递归调用插入函数,插入到左子树中
if (!insert(cur.getLchild(), cur, data)) {
return false;
}
// 若插入成功插入左子树,且左子树长高,进行平衡度检查
if (taller) {
switch (cur.getBf()) {
// 原本左子树比右子树高,需要做左平衡处理
case LH:
leftBalance(cur, parent);
taller = false;
break;
// 原本左子树和右子树等高,现在因为左子树增高而树增高
case EH:
cur.setBf(LH);
taller = true;
break;
// 原本右子树比左子树高,现在左右子树等高
case RH:
cur.setBf(EH);
taller = false;
break;
}

}
} else {
if (!insert(cur.getRchild(), cur, data))
return false;
// 假如taller为ture,则成功插入右子树,且树已长高,进行平衡度检查
if (taller) {

switch (cur.getBf()) {
case LH: // 原本左子树比右子树高,现在左右子树等高
cur.setBf(EH);
taller = false;
break;
case EH: // 原本左右子树等高,现因为右子树增高而树增高
cur.setBf(RH);
taller = true;
break;
case RH: // 原本右子树比左子树高,需要做右平衡处理
rightBalance(cur, parent);
taller = false;
break;
}
}
}

}
return true;
}
return false;
}

@Override
public boolean insert(T data) {
if (root == null) {
root = new BirTreeNode<T>(data);
this.taller = false;
return true;
}

boolean tmp = insert(root, null, data);
taller = false;
return tmp;
}

/**
* 删除节点时左平衡旋转处理
*
* @param cur
*            删除的树的根节点
* @param parent
*            子树cur的双亲节点
*/
private void leftBalance_div(BirTreeNode<T> cur, BirTreeNode<T> parent) {
BirTreeNode<T> p1, p2;
switch (cur.getBf()) {
case LH:
cur.setBf(EH);
shorter = true;
break;
case EH:
cur.setBf(RH);
shorter = false;
break;
case RH:
//
//
p1 = cur.getRchild();
switch (p1.getBf()) {
case EH:
p1.setBf(LH);
cur.setBf(RH);
shorter = false;
leftRotate(cur, parent);
break;
case RH:

p1.setBf(EH);
cur.setBf(EH);
shorter = true;
rightRotate(cur, parent);
break;
case LH:
//
p2 = p1.getLchild();
if (p2.getBf() == EH) {
cur.setBf(EH);
p1.setBf(EH);
} else if (p2.getBf() == RH) {
cur.setBf(LH);
p1.setBf(EH);
} else {
cur.setBf(EH);
p1.setBf(-1);
}
p2.setBf(EH);
rightRotate(p1, cur);
shorter = true;
// 这里要旋转吗?
leftRotate(cur, parent);
}
}
}

/**
* 删除节点时右平衡旋转处理
*
* @param cur
*            要旋转的子树的根节点
* @param parent
*            子树的根节点的双亲节点
*/
private void rightBalance_div(BirTreeNode<T> cur, BirTreeNode<T> parent) {
BirTreeNode<T> p1, p2;
switch (cur.getBf()) {
case RH:
cur.setBf(EH);
shorter = true;
break;
case EH:
cur.setBf(LH);
shorter = false;
break;
case LH:

p1 = cur.getLchild();
switch (p1.getBf()) {
case EH:

// 这里需要旋转
p1.setBf(RH);
cur.setBf(LH);
rightRotate(cur, parent);
shorter = false;
break;
case LH:

p1.setBf(EH);
cur.setBf(EH);
rightRotate(cur, parent);

shorter = true;
break;
case RH:
//
p2 = p1.getRchild();
if (p2.getBf() == EH) {
cur.setBf(EH);
p1.setBf(EH);
} else if (p2.getBf() == LH) {
cur.setBf(RH);
p1.setBf(EH);
} else {
cur.setBf(EH);
p1.setBf(RH);
}
p2.setBf(EH);
leftRotate(p1, cur);
shorter = true;
// 这里需要右旋吗?
rightRotate(cur, parent);
}
}
}

/**
* 删除节点cur,找到替代的节点r
*
* @param cur
*            被删除的节点
* @param childParent
*            替代节点的双亲节点
* @param r
*            替代节点
* @param parent
*            被删除节点的双亲节点
*/
private void delete(BirTreeNode<T> cur, BirTreeNode<T> childParent,
BirTreeNode<T> r, BirTreeNode<T> parent) {
// 寻找替代节点的方法,替代的节点是被删除节点的左子树的最右的节点
//
if (r.getRchild() == null) {
if (parent != null) {

if (parent.getLchild() == cur) {

// 替代被删除的节点
parent.setLchild(r);
// 被替代的节点的双亲节点修改孩子节点
if (childParent.getLchild() == r) {
childParent.setLchild(r.getLchild());
} else if (childParent.getRchild() == r) {
childParent.setRchild(r.getLchild());
}
// 替代的节点接替被删除的左孩子和右孩子
r.setLchild(cur.getLchild());
r.setRchild(cur.getRchild());
} else if (parent.getRchild() == cur) {
// 替代被删除的节点
parent.setRchild(r);
// 被替代的节点的双亲节点修改孩子节点
if (childParent.getLchild() == r) {
childParent.setLchild(r.getLchild());
} else if (childParent.getRchild() == r) {
childParent.setRchild(r.getLchild());
}
// 替代的节点接替被删除的左孩子和右孩子
r.setLchild(cur.getLchild());
r.setRchild(cur.getRchild());
}
} else {

root = r;

if (childParent.getLchild() == r) {

childParent.setLchild(r.getLchild());
} else if (childParent.getRchild() == r) {

childParent.setRchild(r.getLchild());
}
// 到这里为止,已经删除成功,接下来就要进行左子树的平衡处理了
//
root.setLchild(cur.getLchild());
root.setRchild(cur.getRchild());
}
shorter = true;
} else if (r.getRchild() != null) {
// 假如左子树的右子树还没到最后的右子树,则继续递归
delete(cur, r, r.getRchild(), parent);
if (shorter) {
//
//
rightBalance_div(r, root);
}
}
}

/**
* 删除平衡二叉树的数据元素data
*
* @param data
*            要删除的数据元素
* @param cur
*            删除的子树的根节点
* @param parent
*            cur的双亲节点
* @return 成功删除则返回true,否则返回false
*/
private boolean delete(T data, BirTreeNode<T> cur, BirTreeNode<T> parent) {
if (cur != null) {
// 假如删除的数据元素比当前节点小
if (data.compareTo(cur.getData()) < 0) {
delete(data, cur.getLchild(), cur);
if (shorter) {
//
//
leftBalance_div(cur, parent);
}
// 设置树变矮标志
// shorter = false;
return true;
} else if (data.compareTo(cur.getData()) > 0) {
// 假如删除的数据元素比当前数据元素大

delete(data, cur.getRchild(), cur);
if (shorter) {
rightBalance_div(cur, parent);
}
// 设置树变矮的标志,这里不需要
// shorter = false;
return true;
} else {

// 假如当前节点的右子树为空, 删除当前节点,重接左子树
if (cur.getRchild() == null) {
if (parent.getLchild() == cur) {
parent.setLchild(cur.getLchild());
} else if (parent.getRchild() == cur) {
parent.setRchild(cur.getLchild());
}
shorter = true;
} else if (cur.getLchild() == null) {
// 假如当前节点的左子树为空,删除当前节点,重接右子树
if (parent.getLchild() == cur) {
parent.setLchild(cur.getRchild());
} else if (parent.getRchild() == cur) {
parent.setRchild(cur.getRchild());
}

shorter = true;
} else {

// 当左右子树都不为空的时候,寻找替代节点
//
//
delete(cur, cur, cur.getLchild(), parent);

if (shorter) {
leftBalance_div(cur, parent);
}
}
return true;
}
}
return false;
}

@Override
public boolean delete(T data) {
if (data != null) {

return delete(data, root, null);
}
return false;
}

/**
* 升序遍历平衡二叉树
*
* @param cur
*            需要遍历的树的根节点
*/
private void viewASC(BirTreeNode<T> cur) {
if (cur != null) {
viewASC(cur.getLchild());
System.out.print(cur.getData() + " ");
System.out.println("当前标志值为:" + cur.getBf() + "他的左孩子为:"
+ cur.getLchild() + "右孩子为:" + cur.getRchild());
viewASC(cur.getRchild());
}
}

/**
* 降序遍历平衡二叉树
*
* @param cur
*            需要遍历的树的根节点
*/
private void viewDESC(BirTreeNode<T> cur) {
if (cur != null) {
viewDESC(cur.getRchild());
System.out.print(cur.getData() + " ");
viewDESC(cur.getLchild());
}

}

@Override
public void view(int VALUE) {
switch (VALUE) {
case ASC_VALUE:
viewASC(root);
System.out.println();
break;
case DESC_VALUE:
viewDESC(root);
System.out.println();
break;
}

}

@Override
public boolean update(T data, T move) {
if (data != null && move != null) {
this.delete(move);
return this.insert(data);
}
return false;

}

/**
* 求平衡二叉树的深度
*
* @param cur
*            子树的根节点
* @return 返回平衡二叉树的深度
*/
private int getDept(BirTreeNode<T> cur) {
if (cur != null) {
int lc = getDept(cur.getLchild()) + 1;
int rc = getDept(cur.getRchild()) + 1;
return lc > rc ? lc : rc;
}
return 0;
}

@Override
public int getDept() {
return getDept(root);
}

/**
* 清空整棵树
*/
public void clear() {
root = null;
}

/**
* 先序遍历平衡二叉树,做测试用
*
* @param cur
*            子树的根节点
*/
private void view(BirTreeNode<T> cur) {
if (cur != null) {

System.out.print(cur.getData() + " ");

view(cur.getLchild());
view(cur.getRchild());
}
}

/**
* 先序遍历平衡二叉树,做测试用。
*/
public void view() {
view(root);
System.out.println();
}

// 测试
public static void main(String[] args) {
String[] a = { "J", "F", "I", "H", "C", "G", "B", "E", "D", "A" };
AVLSortTree<String> test = new AVLSortTree<>();
for (int i = 0; i < a.length; i++) {
test.insert(a[i]);
}
// // System.out.println(test.insert("H"));
// test.view(ASC_VALUE);
// System.out.println("排序二叉树的深度 " + test.getDept());
// System.out.println("长度?:" + test.getLength());
// // System.out.println("是否为空:" + test.isEmpty());
// test.view();

System.out.println("初次尝试删除:::" + test.delete("A"));
// System.out.println("根节点的标志值:" + test.getRoot().getBf());

// test.delete("J");
// test.delete("C");
// test.delete("D");
// test.delete("G");
test.insert("K");
System.out.println("初次尝试删除:::" + test.delete("B"));
test.insert("L");
test.insert("M");
test.insert("N");
test.insert("O");
test.insert("P");
test.insert("Q");
test.insert("R");
test.insert("S");
test.insert("T");
test.insert("U");
test.insert("V");
test.insert("W");
test.insert("X");
// test.insert("A");
System.out.println("排序二叉树的深度 " + test.getDept());
System.out.println("根节点的数据元素为:" + test.getRoot().getData());
test.view();
test.view(ASC_VALUE);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: