compound-binary-file-js
Version:
This is an implementation of [Compound Binary File v.3](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cfb/53989ce4-7b05-4f8d-829b-d08d6148375b) \ Allows reading existing files, creation of the/write operation
176 lines (168 loc) • 7.51 kB
text/typescript
import {UpdateHandler} from "./UpdateHandler";
import {Color, TreeNode} from "./Node";
import {RedBlackTree} from "./RedBlackTree";
export class DeleteHandler<T> extends UpdateHandler<T> {
private readonly comparator: (o1: T, o2: T) => number;
constructor(tree: RedBlackTree<T>, comparator: (o1: T, o2: T) => number) {
super(tree);
this.comparator = comparator;
}
delete(node: TreeNode<T>): void {
if(!node.hasChildren()) {
if(this.tree.isRoot(node)) {
this.tree.setRoot(null);
} else {
if (node.getColor() === Color.BLACK) {
const sibling = node.sibling();
node.getParent().deleteChild(node);
this.recover(sibling);
} else {
node.getParent().deleteChild(node);
}
}
} else if(node.hasTwoChildren()) {
const substituteWith = this.inOrderPredecessor(node);
this.swap(node, substituteWith);
this.delete(node);
} else {
let substituteWith;
if(node.getRightChild() == null) {
substituteWith = node.getLeftChild();
} else {
substituteWith = node.getRightChild();
}
if(this.tree.isRoot(node)) {
this.tree.setRoot(substituteWith);
substituteWith.setColor(Color.BLACK);
} else if(substituteWith.getColor() === Color.RED || node.getColor() === Color.RED) {
node.getParent().substituteNode(node, substituteWith);
substituteWith.setColor(Color.BLACK);
} else {
const sibling = node.sibling();
node.getParent().substituteNode(node, substituteWith);
this.recover(sibling);
}
}
}
inOrderPredecessor(node: TreeNode<T>): TreeNode<T> {
if(node.getLeftChild() == null) {
return null;
} else {
const allChildren = node.getLeftChild().getChildrenRecursive();
allChildren.push(node.getLeftChild());
allChildren.sort((a: TreeNode<T>, b: TreeNode<T>) => this.comparator(a.getValue(), b.getValue()));
return allChildren[allChildren.length - 1];
}
}
recover(sibling: TreeNode<T>): void {
const siblingColor = sibling.getColor();
const siblingsLeftChild = sibling.getLeftChild();
const siblingsRightChild = sibling.getRightChild();
const siblingLeftChildColor = siblingsLeftChild == null ? Color.BLACK : siblingsLeftChild.getColor();
const siblingRightChildColor = siblingsRightChild == null ? Color.BLACK : siblingsRightChild.getColor();
const isSiblingLeftChild = sibling.getParent().isLeftChild(sibling);
if(siblingColor === Color.BLACK) {
if(siblingLeftChildColor === Color.RED || siblingRightChildColor === Color.RED) {
if(sibling.getParent().isLeftChild(sibling)) {
if(siblingLeftChildColor === Color.RED) {
this.rightRotate(sibling.getParent(), sibling);
siblingsLeftChild.setColor(Color.BLACK);
} else {
this.leftRotate(sibling, sibling.getRightChild());
this.rightRotate(sibling.grandParent(), sibling.getParent());
sibling.setColor(Color.BLACK);
}
} else {
if(siblingRightChildColor === Color.RED) {
this.leftRotate(sibling.getParent(), sibling);
siblingsRightChild.setColor(Color.BLACK);
} else {
this.rightRotate(sibling, sibling.getLeftChild());
this.leftRotate(sibling.grandParent(), sibling.getParent());
sibling.setColor(Color.BLACK);
}
}
} else {
sibling.setColor(Color.RED);
const parent = sibling.getParent();
if(parent.getColor() === Color.BLACK && !this.tree.isRoot(parent)) {
this.recover(parent.sibling());
} else {
parent.setColor(Color.BLACK);
}
}
} else {
const parent = sibling.getParent();
let newSibling;
sibling.setColor(Color.BLACK);
parent.setColor(Color.RED);
if(isSiblingLeftChild) {
newSibling = sibling.getRightChild();
this.rightRotate(sibling.getParent(), sibling);
} else {
newSibling = sibling.getLeftChild();
this.leftRotate(sibling.getParent(), sibling);
}
this.recover(newSibling);
}
}
swap(node1: TreeNode<T>, node2: TreeNode<T>): void {
if(node1.getParent() === node2) {
this.swapChildParent(node2, node1);
} else if(node2.getParent() === node1) {
this.swapChildParent(node1, node2);
} else {
const node1Parent = node1.getParent();
const node1LeftChild = node1.getLeftChild();
const node1RightChild = node1.getRightChild();
const node2Parent = node2.getParent();
const node2LeftChild = node2.getLeftChild();
const node2RightChild = node2.getRightChild();
const node1Color = node1.getColor();
const node2Color = node2.getColor();
node1.setLeftChild(node2LeftChild);
node1.setRightChild(node2RightChild);
node2.setLeftChild(node1LeftChild);
node2.setRightChild(node1RightChild);
node1.setColor(node2Color);
node2.setColor(node1Color);
if(node1Parent == null) {
this.tree.setRoot(node2);
} else {
node1Parent.substituteNode(node1, node2);
}
if(node2Parent == null) {
this.tree.setRoot(node1);
} else {
node2Parent.substituteNode(node2, node1);
}
}
}
swapChildParent(parent: TreeNode<T>, child: TreeNode<T>): void {
const parentColor = parent.getColor();
const childColor = child.getColor();
const leftGrandChild = child.getLeftChild();
const rightGrandChild = child.getRightChild();
const grandParent = parent.getParent();
if(grandParent == null) {
this.tree.setRoot(child);
} else if(grandParent.isLeftChild(parent)) {
grandParent.setLeftChild(child);
} else {
grandParent.setRightChild(child);
}
if(parent.isLeftChild(child)) {
const rightChild = parent.getRightChild();
child.setLeftChild(parent);
child.setRightChild(rightChild);
} else {
const leftChild = parent.getLeftChild();
child.setRightChild(parent);
child.setLeftChild(leftChild);
}
child.setColor(parentColor);
parent.setLeftChild(leftGrandChild);
parent.setRightChild(rightGrandChild);
parent.setColor(childColor);
}
}