fix: Fix bug in BinaryTree.print to support undefined, null, and NIL. Fix #106

This commit is contained in:
Revone 2024-10-31 16:18:51 +13:00
parent 0a8b9265cc
commit 9ace395564
5 changed files with 76 additions and 34 deletions

View file

@ -1681,20 +1681,14 @@ export class BinaryTree<
beginRoot: BTNKeyOrNodeOrEntry<K, V, NODE> | R = this._root,
options?: BinaryTreePrintOptions
): string {
const opts = { isShowUndefined: false, isShowNull: false, isShowRedBlackNIL: false, ...options };
const opts = { isShowUndefined: false, isShowNull: true, isShowRedBlackNIL: false, ...options };
beginRoot = this.ensureNode(beginRoot);
let output = '';
if (!beginRoot) return output;
if (opts.isShowUndefined)
output += `U for undefined
`;
if (opts.isShowNull)
output += `N for null
`;
if (opts.isShowRedBlackNIL)
output += `S for Sentinel Node(NIL)
`;
if (opts.isShowUndefined) output += `U for undefined\n`;
if (opts.isShowNull) output += `N for null\n`;
if (opts.isShowRedBlackNIL) output += `S for Sentinel Node(NIL)\n`;
const display = (root: OptBTNOrNull<NODE>): void => {
const [lines, , ,] = this._displayAux(root, opts);
@ -1709,6 +1703,10 @@ export class BinaryTree<
return output;
}
override print(options?: BinaryTreePrintOptions, beginRoot: BTNKeyOrNodeOrEntry<K, V, NODE> | R = this._root) {
console.log(this.toVisual(beginRoot, options));
}
protected _dfs<C extends BTNCallback<NODE>>(
callback?: C,
pattern?: DFSOrderPattern,

View file

@ -310,28 +310,26 @@ export class BST<
if (!isBalanceAdd) {
for (const kve of keysOrNodesOrEntriesOrRaws) {
const value = valuesIterator?.next().value;
const nn = this.add(kve, value);
inserted.push(nn);
inserted.push(this.add(kve, value));
}
return inserted;
}
const realBTNExemplars: (R | BTNPureKeyOrNodeOrEntry<K, V, NODE>)[] = [];
const isRealBTNExemplar = (
kve: BTNKeyOrNodeOrEntry<K, V, NODE> | R
): kve is BTNPureKeyOrNodeOrEntry<K, V, NODE> => {
if (kve === undefined || kve === null) return false;
return !(this.isEntry(kve) && (kve[0] === undefined || kve[0] === null));
};
const realBTNExemplars: {
key: R | BTNKeyOrNodeOrEntry<K, V, NODE>;
value: V | undefined;
orgIndex: number;
}[] = [];
let i = 0;
for (const kve of keysOrNodesOrEntriesOrRaws) {
if (isRealBTNExemplar(kve)) realBTNExemplars.push(kve);
realBTNExemplars.push({ key: kve, value: valuesIterator?.next().value, orgIndex: i });
i++;
}
let sorted: (R | BTNPureKeyOrNodeOrEntry<K, V, NODE>)[] = [];
let sorted: { key: R | BTNKeyOrNodeOrEntry<K, V, NODE>; value: V | undefined; orgIndex: number }[] = [];
sorted = realBTNExemplars.sort((a, b) => {
sorted = realBTNExemplars.sort(({ key: a }, { key: b }) => {
let keyA: K | undefined | null, keyB: K | undefined | null;
if (this.isEntry(a)) keyA = a[0];
else if (this.isRealNode(a)) keyA = a.key;
@ -355,12 +353,12 @@ export class BST<
return 0;
});
const _dfs = (arr: (R | BTNPureKeyOrNodeOrEntry<K, V, NODE>)[]) => {
const _dfs = (arr: { key: R | BTNKeyOrNodeOrEntry<K, V, NODE>; value: V | undefined; orgIndex: number }[]) => {
if (arr.length === 0) return;
const mid = Math.floor((arr.length - 1) / 2);
const newNode = this.add(arr[mid]);
inserted.push(newNode);
const { key, value, orgIndex } = arr[mid];
inserted[orgIndex] = this.add(key, value);
_dfs(arr.slice(0, mid));
_dfs(arr.slice(mid + 1));
};
@ -374,8 +372,8 @@ export class BST<
const [l, r] = popped;
if (l <= r) {
const m = l + Math.floor((r - l) / 2);
const newNode = this.add(sorted[m]);
inserted.push(newNode);
const { key, value, orgIndex } = sorted[m];
inserted[orgIndex] = this.add(key, value);
stack.push([m + 1, r]);
stack.push([l, m - 1]);
}

View file

@ -292,6 +292,26 @@ describe('AVLTree', () => {
// You can add more specific assertions to check the tree's balance and structure.
});
it('should addMany undefined and null', () => {
const avl = new AVLTree<number, string>();
const addManyWithUndefined = avl.addMany([1, undefined, 3]);
expect(addManyWithUndefined).toEqual([true, false, true]);
expect(avl.get(undefined)).toBe(undefined);
const addManyWithNull = avl.addMany([1, null, 3, 4]);
expect(addManyWithNull).toEqual([true, false, true, true]);
const addManyEntriesWithNull = avl.addMany([
[1, '1'],
[null, 'null'],
[3, '3'],
[4, '4']
]);
expect(addManyEntriesWithNull).toEqual([true, false, true, true]);
expect(avl.get(null)).toBe(undefined);
const node0 = avl.add(0, '0');
expect(node0).toBe(true);
expect(avl.get(0)).toBe('0');
});
it('should balance the tree using _balanceLR when nodes are deleted', () => {
const avlTree = new AVLTree();
avlTree.add([10, 'A']);

View file

@ -105,6 +105,27 @@ describe('BinaryTree addMany', () => {
expect(tree.getNodeByKey(4)?.value).toBe(44);
expect(tree.getNodeByKey(1)?.value).toBe(1);
});
it('should addMany undefined and null', () => {
const binaryTree = new BinaryTree<number, string>();
const addManyWithUndefined = binaryTree.addMany([1, undefined, 3]);
expect(addManyWithUndefined).toEqual([true, false, true]);
expect(binaryTree.get(undefined)).toBe(undefined);
const addManyWithNull = binaryTree.addMany([1, null, 3, 4]);
expect(addManyWithNull).toEqual([true, true, true, true]);
const addManyEntriesWithNull = binaryTree.addMany([
[1, '1'],
[null, 'null'],
[3, '3'],
[4, '4']
]);
expect(addManyEntriesWithNull).toEqual([true, true, true, true]);
expect(binaryTree.get(null)).toBe(undefined);
expect(binaryTree.getNode(null)).toBe(null);
const node0 = binaryTree.add(0, '0');
expect(node0).toBe(true);
expect(binaryTree.get(0)).toBe('0');
});
});
describe('BinaryTree', () => {

View file

@ -16,22 +16,27 @@ describe('BST operations test', () => {
expect(isAdd0).toBe(true);
expect(bst.get(0)).toBe('0');
});
it('should addMany undefined and null', () => {
const bst = new BST<number, string>();
const addManyWithUndefined = bst.addMany([1, undefined, 3]);
// TODO
// expect(addManyWithUndefined).toEqual([true, false, true]);
expect(addManyWithUndefined).toEqual([true, true]);
expect(addManyWithUndefined).toEqual([true, false, true]);
expect(bst.get(undefined)).toBe(undefined);
const addManyWithNull = bst.addMany([1, null, 3, 4]);
// TODO
// expect(addManyWithNull).toEqual([false, false, false, true]);
expect(addManyWithNull).toEqual([true, true, true]);
expect(addManyWithNull).toEqual([true, false, true, true]);
const addManyEntriesWithNull = bst.addMany([
[1, '1'],
[null, 'null'],
[3, '3'],
[4, '4']
]);
expect(addManyEntriesWithNull).toEqual([true, false, true, true]);
expect(bst.get(null)).toBe(undefined);
const node0 = bst.add(0, '0');
expect(node0).toBe(true);
expect(bst.get(0)).toBe('0');
});
it('should perform various operations on a Binary Search Tree with numeric values', () => {
const bst = new BST<number, number>();
expect(bst).toBeInstanceOf(BST);