📄 doubleorderedmap.java
字号:
* do a rotate right. standard fare in the world of balanced trees
*
* @param node the node to be rotated
* @param index KEY or VALUE
*/
private void rotateRight(final Node node, final int index) {
Node leftChild = node.getLeft(index);
node.setLeft(leftChild.getRight(index), index);
if (leftChild.getRight(index) != null) {
leftChild.getRight(index).setParent(node, index);
}
leftChild.setParent(node.getParent(index), index);
if (node.getParent(index) == null) {
// node was the root ... now its left child is the root
rootNode[index] = leftChild;
} else if (node.getParent(index).getRight(index) == node) {
node.getParent(index).setRight(leftChild, index);
} else {
node.getParent(index).setLeft(leftChild, index);
}
leftChild.setRight(node, index);
node.setParent(leftChild, index);
}
/**
* complicated red-black insert stuff. Based on Sun's TreeMap
* implementation, though it's barely recognizable any more
*
* @param insertedNode the node to be inserted
* @param index KEY or VALUE
*/
private void doRedBlackInsert(final Node insertedNode, final int index) {
Node currentNode = insertedNode;
makeRed(currentNode, index);
while ((currentNode != null) && (currentNode != rootNode[index])
&& (isRed(currentNode.getParent(index), index))) {
if (isLeftChild(getParent(currentNode, index), index)) {
Node y = getRightChild(getGrandParent(currentNode, index),
index);
if (isRed(y, index)) {
makeBlack(getParent(currentNode, index), index);
makeBlack(y, index);
makeRed(getGrandParent(currentNode, index), index);
currentNode = getGrandParent(currentNode, index);
} else {
if (isRightChild(currentNode, index)) {
currentNode = getParent(currentNode, index);
rotateLeft(currentNode, index);
}
makeBlack(getParent(currentNode, index), index);
makeRed(getGrandParent(currentNode, index), index);
if (getGrandParent(currentNode, index) != null) {
rotateRight(getGrandParent(currentNode, index),
index);
}
}
} else {
// just like clause above, except swap left for right
Node y = getLeftChild(getGrandParent(currentNode, index),
index);
if (isRed(y, index)) {
makeBlack(getParent(currentNode, index), index);
makeBlack(y, index);
makeRed(getGrandParent(currentNode, index), index);
currentNode = getGrandParent(currentNode, index);
} else {
if (isLeftChild(currentNode, index)) {
currentNode = getParent(currentNode, index);
rotateRight(currentNode, index);
}
makeBlack(getParent(currentNode, index), index);
makeRed(getGrandParent(currentNode, index), index);
if (getGrandParent(currentNode, index) != null) {
rotateLeft(getGrandParent(currentNode, index), index);
}
}
}
}
makeBlack(rootNode[index], index);
}
/**
* complicated red-black delete stuff. Based on Sun's TreeMap
* implementation, though it's barely recognizable any more
*
* @param deletedNode the node to be deleted
*/
private void doRedBlackDelete(final Node deletedNode) {
for (int index = FIRST_INDEX; index < NUMBER_OF_INDICES; index++) {
// if deleted node has both left and children, swap with
// the next greater node
if ((deletedNode.getLeft(index) != null)
&& (deletedNode.getRight(index) != null)) {
swapPosition(nextGreater(deletedNode, index), deletedNode,
index);
}
Node replacement = ((deletedNode.getLeft(index) != null)
? deletedNode.getLeft(index)
: deletedNode.getRight(index));
if (replacement != null) {
replacement.setParent(deletedNode.getParent(index), index);
if (deletedNode.getParent(index) == null) {
rootNode[index] = replacement;
} else if (deletedNode
== deletedNode.getParent(index).getLeft(index)) {
deletedNode.getParent(index).setLeft(replacement, index);
} else {
deletedNode.getParent(index).setRight(replacement, index);
}
deletedNode.setLeft(null, index);
deletedNode.setRight(null, index);
deletedNode.setParent(null, index);
if (isBlack(deletedNode, index)) {
doRedBlackDeleteFixup(replacement, index);
}
} else {
// replacement is null
if (deletedNode.getParent(index) == null) {
// empty tree
rootNode[index] = null;
} else {
// deleted node had no children
if (isBlack(deletedNode, index)) {
doRedBlackDeleteFixup(deletedNode, index);
}
if (deletedNode.getParent(index) != null) {
if (deletedNode
== deletedNode.getParent(index)
.getLeft(index)) {
deletedNode.getParent(index).setLeft(null, index);
} else {
deletedNode.getParent(index).setRight(null,
index);
}
deletedNode.setParent(null, index);
}
}
}
}
shrink();
}
/**
* complicated red-black delete stuff. Based on Sun's TreeMap
* implementation, though it's barely recognizable any more. This
* rebalances the tree (somewhat, as red-black trees are not
* perfectly balanced -- perfect balancing takes longer)
*
* @param replacementNode the node being replaced
* @param index KEY or VALUE
*/
private void doRedBlackDeleteFixup(final Node replacementNode,
final int index) {
Node currentNode = replacementNode;
while ((currentNode != rootNode[index])
&& (isBlack(currentNode, index))) {
if (isLeftChild(currentNode, index)) {
Node siblingNode =
getRightChild(getParent(currentNode, index), index);
if (isRed(siblingNode, index)) {
makeBlack(siblingNode, index);
makeRed(getParent(currentNode, index), index);
rotateLeft(getParent(currentNode, index), index);
siblingNode = getRightChild(getParent(currentNode, index), index);
}
if (isBlack(getLeftChild(siblingNode, index), index)
&& isBlack(getRightChild(siblingNode, index),
index)) {
makeRed(siblingNode, index);
currentNode = getParent(currentNode, index);
} else {
if (isBlack(getRightChild(siblingNode, index), index)) {
makeBlack(getLeftChild(siblingNode, index), index);
makeRed(siblingNode, index);
rotateRight(siblingNode, index);
siblingNode =
getRightChild(getParent(currentNode, index), index);
}
copyColor(getParent(currentNode, index), siblingNode,
index);
makeBlack(getParent(currentNode, index), index);
makeBlack(getRightChild(siblingNode, index), index);
rotateLeft(getParent(currentNode, index), index);
currentNode = rootNode[index];
}
} else {
Node siblingNode = getLeftChild(getParent(currentNode, index), index);
if (isRed(siblingNode, index)) {
makeBlack(siblingNode, index);
makeRed(getParent(currentNode, index), index);
rotateRight(getParent(currentNode, index), index);
siblingNode = getLeftChild(getParent(currentNode, index), index);
}
if (isBlack(getRightChild(siblingNode, index), index)
&& isBlack(getLeftChild(siblingNode, index), index)) {
makeRed(siblingNode, index);
currentNode = getParent(currentNode, index);
} else {
if (isBlack(getLeftChild(siblingNode, index), index)) {
makeBlack(getRightChild(siblingNode, index), index);
makeRed(siblingNode, index);
rotateLeft(siblingNode, index);
siblingNode =
getLeftChild(getParent(currentNode, index), index);
}
copyColor(getParent(currentNode, index), siblingNode,
index);
makeBlack(getParent(currentNode, index), index);
makeBlack(getLeftChild(siblingNode, index), index);
rotateRight(getParent(currentNode, index), index);
currentNode = rootNode[index];
}
}
}
makeBlack(currentNode, index);
}
/**
* swap two nodes (except for their content), taking care of
* special cases where one is the other's parent ... hey, it
* happens.
*
* @param x one node
* @param y another node
* @param index KEY or VALUE
*/
private void swapPosition(final Node x, final Node y, final int index) {
// Save initial values.
Node xFormerParent = x.getParent(index);
Node xFormerLeftChild = x.getLeft(index);
Node xFormerRightChild = x.getRight(index);
Node yFormerParent = y.getParent(index);
Node yFormerLeftChild = y.getLeft(index);
Node yFormerRightChild = y.getRight(index);
boolean xWasLeftChild =
(x.getParent(index) != null)
&& (x == x.getParent(index).getLeft(index));
boolean yWasLeftChild =
(y.getParent(index) != null)
&& (y == y.getParent(index).getLeft(index));
// Swap, handling special cases of one being the other's parent.
if (x == yFormerParent) { // x was y's parent
x.setParent(y, index);
if (yWasLeftChild) {
y.setLeft(x, index);
y.setRight(xFormerRightChild, index);
} else {
y.setRight(x, index);
y.setLeft(xFormerLeftChild, index);
}
} else {
x.setParent(yFormerParent, index);
if (yFormerParent != null) {
if (yWasLeftChild) {
yFormerParent.setLeft(x, index);
} else {
yFormerParent.setRight(x, index);
}
}
y.setLeft(xFormerLeftChild, index);
y.setRight(xFormerRightChild, index);
}
if (y == xFormerParent) { // y was x's parent
y.setParent(x, index);
if (xWasLeftChild) {
x.setLeft(y, index);
x.setRight(yFormerRightChild, index);
} else {
x.setRight(y, index);
x.setLeft(yFormerLeftChild, index);
}
} else {
y.setParent(xFormerParent, index);
if (xFormerParent != null) {
if (xWasLeftChild) {
xFormerParent.setLeft(y, index);
} else {
xFormerParent.setRight(y, index);
}
}
x.setLeft(yFormerLeftChild, index);
x.setRight(yFormerRightChild, index);
}
// Fix children's parent pointers
if (x.getLeft(index) != null) {
x.getLeft(index).setParent(x, index);
}
if (x.getRight(index) != null) {
x.getRight(index).setParent(x, index);
}
if (y.getLeft(index) != null) {
y.getLeft(index).setParent(y, index);
}
if (y.getRight(index) != null) {
y.getRight(index).setParent(y, index);
}
x.swapColors(y, index);
// Check if root changed
if (rootNode[index] == x) {
rootNode[index] = y;
} else if (rootNode[index] == y) {
rootNode[index] = x;
}
}
/**
* check if an object is fit to be proper input ... has to be
* Comparable and non-null
*
* @param o the object being checked
* @param index KEY or VALUE (used to put the right word in the
* exception message)
*
* @throws NullPointerException if o is null
* @throws ClassCastException if o is not Comparable
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -