您的位置:首页 > 编程语言 > Java开发

JAVA实践红黑树-小试牛刀

2016-08-24 20:42 197 查看

前言

第一感觉是和AVL树差别不是特别大,没有很直观的感受到效率的巨大提升,作为一个小小的强迫症患者,还是AVL树更好看。

不过讲道理,平衡被破坏次数相同情况下,红黑树的确少了那么一些旋转。。。

因为插入节点后平衡被破坏时,红黑树的会选择旋转或变色。

AVL树则只有旋转。

另外我发现其他的大神写法,跟我的有点差距。。。有心人可以帮我瞄一眼,我是不是哪里错了,在此先谢过了~~

另外一个参考网站、博客、PDF:

红黑树的可视化,插入、删除节点都有动画效果哦~

神奇的讲义,略的比较多,但就胜在简略

一个大神的博客,思路清晰,详细,非常值得参考

实现功能

插入

还有个伪删除。。。可以忽略,加个布尔变量的事。

不然咋叫小试牛刀呢(逃

参考

首先瞄一眼红黑树的性质



再看看长啥样



关于插入的那些事



























再次汇总



代码实现

public class RBTree<T extends Comparable<T>> {

public static void main(String[] args) {

///*
int[] testNum = new int[]{15, 1, 3, 6, 8, 20, 22, 43, 67};
RBTree<Integer> fuck = new RBTree<Integer>();
for (int i = 0; i < testNum.length; i++) {
fuck.insertNode(testNum[i]);
}
System.out.println(fuck.root.data);
//*/
/*
RBTree<Character> fuck = new RBTree<Character>();
fuck.insertNode('F');
fuck.insertNode('G');
fuck.insertNode('D');
fuck.insertNode('B');
fuck.insertNode('C');
System.out.println(fuck.root.data);
*/
}

private static final boolean RED = true;
private static final boolean BLACK = false;

private TreeNode<T> root;

/**
* 插入一个新的节点,插入完毕后符合红黑树性质
*
* @param data  需要插入的数据
*/
public void insertNode(T data) {
TreeNode<T> curr;
TreeNode<T> parent = toTargetParent(data);
if (parent == null) {
curr = root = new TreeNode<T>(data);
} else {
if (data.compareTo(parent.data) < 0) {
curr = parent.left = new TreeNode<T>(data);
curr.parent = parent;
} else {
curr = parent.right = new TreeNode<T>(data);
curr.parent = parent;
}
}
fixupTree(curr);
}

/**
* 修复红黑树的不平衡状态
*
* @param node  新增节点
*/
private void fixupTree(TreeNode node) {
TreeNode parent = null, grandParent = null;
boolean parentColor = false, uncleColor = false;
if (node != root) {
parent = node.parent;
grandParent = parent.parent;
parentColor = parent.color;
uncleColor = getUncleColor(node);
}
//父节点为空表示其为根节点
if (parent == null && node.color == RED) {
node.color = BLACK;
} else if (parentColor == RED && uncleColor == RED) {
changeColor(grandParent);
//再次判断根节点是否满足要求
fixupTree(grandParent);
} else if (parentColor == RED && uncleColor == BLACK) {
dispatchRotation(grandParent, parent, node);
}
}

/**
* 判断属于哪种四种情况,LL、LR、RR、RL,使用正确的旋转
*
* @param grandParent   祖父节点
* @param parent    父节点
* @param child     新增节点
*/
private void dispatchRotation(TreeNode grandParent, TreeNode parent, TreeNode child) {
if (grandParent.left == parent) {
if (parent.left == child) {
rightRotation(grandParent);
} else {
leftRotation(parent);
rightRotation(grandParent);
}
} else {
if (parent.left == child) {
rightRotation(parent);
leftRotation(grandParent);
} else {
leftRotation(grandParent);
}
}
}

/**
*  改变祖父节点以及两个子节点的颜色
*
* @param grandParent   传入新增节点的祖父
*/
private void changeColor(TreeNode grandParent) {
grandParent.color = RED;
if (grandParent.left != null) {
grandParent.left.color = BLACK;
}
if (grandParent.right != null) {
grandParent.right.color = BLACK;
}
}

/**
* 返回叔叔节点的颜色
*
* @param node 一个节点
* @return 其叔叔节点的颜色
*/
private boolean getUncleColor(TreeNode node) {
TreeNode parent = node.parent;
//如果当前结点的祖父是空的,说明是其父节点是根节点
return getBrotherColor(parent.parent == null ? node : parent);
}

/**
* 返回兄弟节点的颜色
*
* @param child 传入节点
* @return 返回兄弟节点的颜色
*/
private boolean getBrotherColor(TreeNode child) {
TreeNode parent = child.parent;
if (parent.left == child && parent.right != null) {
return parent.right.color;
} else if (parent.right == child && parent.left != null) {
return parent.left.color;
} else {
return BLACK;
}
}

/**
*  将传入的节点的右子节点提升为新的父节点,传入节点降为其右子节点
*  注意颜色、父节点需要处理,务必要清除传入节点的右子节点,因为其已经被提升了父节点了。
* @param curr  一个节点
*/
private void leftRotation(TreeNode curr) {
TreeNode tParent = curr.right;
tParent.parent = curr.parent;
tParent.color = BLACK;
//新父节点的左子节点,放在传入节点的右边
curr.right = tParent.left;
if (tParent.left != null) {
tParent.left.parent = curr;
}
//降为子节点前的数据整理
curr.color = RED;
curr.parent = tParent;
tParent.left = curr;
setChild(curr, tParent);
}

/**
*  将传入的节点的左子节点提升为新的父节点,传入节点降为其右子节点
*  注意颜色、父节点需要处理,务必要清除传入节点的左子节点,因为其已经被提升了父节点了。
* @param curr  一个节点
*/
private void rightRotation(TreeNode curr) {
//新的父节点
TreeNode tParent = curr.left;
tParent.parent = curr.parent;
tParent.color = BLACK;
//新父节点的右子节点,放在传入节点的左边
curr.left = tParent.right;
if (tParent.right != null) {
tParent.right.parent = curr;
}
//传入节点降为子节点前的数据整理
curr.color = RED;
curr.parent = tParent;
tParent.right = curr;
setChild(curr, tParent);
}

/**
* 使旋转在树中生效
*
* @param roNode    被旋转的节点
* @param newParent 被旋转之后的父节点
*/
private void setChild(TreeNode roNode, TreeNode newParent) {
TreeNode roNodeParent = newParent.parent;
if (roNodeParent == null) {
root = newParent;
} else if (roNodeParent.left == roNode) {
roNodeParent.left = newParent;
} else {
roNodeParent.right = newParent;
}
}

/**
*  调到data存放位置的父节点处
* @param data  用于对比的数据
* @return  data可存放处的父节点
*/
private TreeNode<T> toTargetParent(T data) {
TreeNode<T> curr = root;
TreeNode<T> parent = root;
while (curr != null) {
parent = curr;
if (data.compareTo(curr.data) < 0) {
curr = curr.left;
} else {
curr = curr.right;
}
}
return parent;
}

/**
* 内部节点
*/
static class TreeNode<T extends Comparable<T>> {
T data;
boolean color;
//伪删除
boolean isDeleted;
TreeNode<T> left;
TreeNode<T> right;
TreeNode<T> parent;

TreeNode(T data, boolean color) {
this.data = data;
this.color = color;
}

TreeNode(T data) {
this.data = data;
this.color = RED;
}
}
}


结果

8


经过验证,长这样!



END

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息