assert myRight[0] == 0 : whatWasDoing + "\n" + myRight[0];
assert myBlack.get(0) : whatWasDoing;
final int[] lastBlackHeight = new int[] {-1};
visitULR(0, new IntIntToInt() {
@Override
public int invoke(int x, int bh) {
if (x == 0)
return bh;
// 1. Binary search tree property
long k = myKeys[x];
int l = myLeft[x];
long lk = myKeys[l];
if (l != 0)
assert lk < k : debugMegaPrint(whatWasDoing, x);
int r = myRight[x];
long rk = myKeys[r];
if (r != 0)
assert rk > k : debugMegaPrint(whatWasDoing, x);
// 2. Red-black tree property-1: If node is red, all its children are black
boolean nodeIsRed = !myBlack.get(x);
boolean bothChildrenAreBlack = myBlack.get(l) && myBlack.get(r);
assert !(nodeIsRed && !bothChildrenAreBlack) : debugMegaPrint(whatWasDoing, x);
// 3. Read-black tree property-2: number of black nodes (black height) are equal for all paths from root to leaves
if (myBlack.get(x))
bh += 1;
if (l == 0 || r == 0) {
// We're in a leaf: check our black height against the previous one or record if we're the first
if (lastBlackHeight[0] < 0)
lastBlackHeight[0] = bh;
else
assert lastBlackHeight[0] == bh : debugMegaPrint(whatWasDoing + ' ' + lastBlackHeight[0] + ' ' + bh, x);
}
return bh;
}
});
// 4. Red-black tree property-2: Root is black
assert myBlack.get(myRoot) : debugMegaPrint(whatWasDoing, myRoot);
// 5. Height estimate is not less than any actual path height
final int heightEstimate = height(size());
visitULR(0, new IntIntToInt() {
@Override
public int invoke(int x, int h) {
if (myLeft[x] == 0 && myRight[x] == 0) {
// we're at the bottom
assert heightEstimate >= h : whatWasDoing + "\n" + h + ' ' + heightEstimate + ' ' + size() + ' ' + myFront;
}
return h + 1;
}
});
// any unreachable node should be contained in myRemoved
final BitSet unremoved = new BitSet(myFront);
visitULR(0, new IntIntToInt() {
@Override
public int invoke(int x, int _) {
if (x != 0) unremoved.set(x);
return _;
}