feat: The print method supports switches for empty nodes and guardian nodes. refactor: It eliminates some unnecessary type definitions.

This commit is contained in:
Revone 2023-11-21 17:30:57 +08:00
parent cbe6dedfd6
commit 54c74f9af6
6 changed files with 103 additions and 77 deletions

View file

@ -8,7 +8,7 @@ All notable changes to this project will be documented in this file.
- [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
- [`auto-changelog`](https://github.com/CookPete/auto-changelog)
## [v1.46.7](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
## [v1.46.8](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
### Changes

View file

@ -48,15 +48,15 @@
"type": "git",
"url": "git+https://github.com/zrwusa/data-structure-typed.git"
},
"bugs": {
"url": "https://github.com/zrwusa/data-structure-typed/issues"
},
"homepage": "https://data-structure-typed-docs.vercel.app",
"author": "Tyler Zeng <zrwusa@gmail.com>",
"license": "MIT",
"publishConfig": {
"@zrwusa:registry": "https://npm.pkg.github.com"
},
"bugs": {
"url": "https://github.com/zrwusa/data-structure-typed/issues"
},
"homepage": "https://data-structure-typed-docs.vercel.app",
"devDependencies": {
"@swc/core": "^1.3.96",
"@types/benchmark": "^2.1.3",

View file

@ -7,7 +7,14 @@
*/
import type { BinaryTreeNodeNested, BinaryTreeOptions, BTNCallback, BTNKey } from '../../types';
import { BiTreeDeleteResult, DFSOrderPattern, FamilyPosition, IterationType } from '../../types';
import {
BinaryTreePrintOptions,
BiTreeDeleteResult,
DFSOrderPattern,
FamilyPosition,
IterationType,
NodeDisplayLayout
} from '../../types';
import { IBinaryTree } from '../../interfaces';
import { trampoline } from '../../utils';
import { Queue } from '../queue';
@ -1727,16 +1734,25 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
/**
* The `print` function is used to display a binary tree structure in a visually appealing way.
* @param {N | null | undefined} beginRoot - The `root` parameter is of type `BTNKey | N | null |
* @param {BTNKey | N | null | undefined} [beginRoot=this.root] - The `root` parameter is of type `BTNKey | N | null |
* undefined`. It represents the root node of a binary tree. The root node can have one of the
* following types:
* @param {BinaryTreePrintOptions} [options={ isShowUndefined: false, isShowNull: false, isShowRedBlackNIL: false}] - Options object that controls printing behavior. You can specify whether to display undefined, null, or sentinel nodes.
*/
print(beginRoot: BTNKey | N | null | undefined = this.root): void {
print(beginRoot: BTNKey | N | null | undefined = this.root, options?: BinaryTreePrintOptions): void {
const opts = { isShowUndefined: false, isShowNull: false, isShowRedBlackNIL: false, ...options };
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return;
if (opts.isShowUndefined) console.log(`U for undefined
`);
if (opts.isShowNull) console.log(`N for null
`);
if (opts.isShowRedBlackNIL) console.log(`S for Sentinel Node
`);
const display = (root: N | null | undefined): void => {
const [lines, , ,] = this._displayAux(root);
const [lines, , ,] = this._displayAux(root, opts);
for (const line of lines) {
console.log(line);
}
@ -1745,39 +1761,54 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
display(beginRoot);
}
protected _displayAux(node: N | null | undefined): [string[], number, number, number] {
if (!node) {
return [['─'], 1, 0, 0];
protected _displayAux(node: N | null | undefined, options: BinaryTreePrintOptions): NodeDisplayLayout {
const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
const emptyDisplayLayout = <NodeDisplayLayout>[['─'], 1, 0, 0];
// Check if node is null or undefined or key is NaN
if (node === null && !isShowNull) {
return emptyDisplayLayout;
} else if (node === undefined && !isShowUndefined) {
return emptyDisplayLayout;
} else if (node !== null && node !== undefined && isNaN(node.key) && !isShowRedBlackNIL) {
return emptyDisplayLayout;
} else if (node !== null && node !== undefined) {
// Display logic of normal nodes
const key = node.key, line = isNaN(key) ? 'S' : key.toString(), width = line.length;
return _buildNodeDisplay(line, width, this._displayAux(node.left, options), this._displayAux(node.right, options))
} else {
// For cases where none of the conditions are met, null, undefined, and NaN nodes are not displayed
const line = node === undefined ? 'U' : 'N', width = line.length;
return _buildNodeDisplay(line, width, [[''], 1, 0, 0], [[''], 1, 0, 0])
}
const line = node.key.toString();
const width = line.length;
function _buildNodeDisplay(line: string, width: number, left: NodeDisplayLayout, right: NodeDisplayLayout) {
const [leftLines, leftWidth, leftHeight, leftMiddle] = left;
const [rightLines, rightWidth, rightHeight, rightMiddle] = right;
const firstLine = ' '.repeat(Math.max(0, leftMiddle + 1))
+ '_'.repeat(Math.max(0, leftWidth - leftMiddle - 1))
+ line
+ '_'.repeat(Math.max(0, rightMiddle))
+ ' '.repeat(Math.max(0, rightWidth - rightMiddle));
if (!node.left && !node.right) {
return [[line], width, 1, Math.floor(width / 2)];
const secondLine = (leftHeight > 0 ? ' '.repeat(leftMiddle) + '/' + ' '.repeat(leftWidth - leftMiddle - 1) : ' '.repeat(leftWidth))
+ ' '.repeat(width)
+ (rightHeight > 0 ? ' '.repeat(rightMiddle) + '\\' + ' '.repeat(rightWidth - rightMiddle - 1) : ' '.repeat(rightWidth));
const mergedLines = [firstLine, secondLine];
for (let i = 0; i < Math.max(leftHeight, rightHeight); i++) {
const leftLine = i < leftHeight ? leftLines[i] : ' '.repeat(leftWidth);
const rightLine = i < rightHeight ? rightLines[i] : ' '.repeat(rightWidth);
mergedLines.push(leftLine + ' '.repeat(width) + rightLine);
}
return <NodeDisplayLayout>[mergedLines, leftWidth + width + rightWidth, Math.max(leftHeight, rightHeight) + 2, leftWidth + Math.floor(width / 2)];
}
const [leftLines, leftWidth, leftHeight, leftMiddle] = node.left ? this._displayAux(node.left) : [[''], 0, 0, 0];
const [rightLines, rightWidth, rightHeight, rightMiddle] = node.right ? this._displayAux(node.right) : [[''], 0, 0, 0];
const firstLine = ' '.repeat(Math.max(0, leftMiddle + 1))
+ '_'.repeat(Math.max(0, leftWidth - leftMiddle - 1))
+ line
+ '_'.repeat(Math.max(0, rightMiddle))
+ ' '.repeat(Math.max(0, rightWidth - rightMiddle));
const secondLine = (leftHeight > 0 ? ' '.repeat(leftMiddle) + '/' + ' '.repeat(leftWidth - leftMiddle - 1) : ' '.repeat(leftWidth))
+ ' '.repeat(width)
+ (rightHeight > 0 ? ' '.repeat(rightMiddle) + '\\' + ' '.repeat(rightWidth - rightMiddle - 1) : ' '.repeat(rightWidth));
const mergedLines = [firstLine, secondLine];
for (let i = 0; i < Math.max(leftHeight, rightHeight); i++) {
const leftLine = i < leftHeight ? leftLines[i] : ' '.repeat(leftWidth);
const rightLine = i < rightHeight ? rightLines[i] : ' '.repeat(rightWidth);
mergedLines.push(leftLine + ' '.repeat(width) + rightLine);
}
return [mergedLines, leftWidth + width + rightWidth, Math.max(leftHeight, rightHeight) + 2, leftWidth + Math.floor(width / 2)];
}
protected _defaultOneParamCallback = (node: N) => node.key;

View file

@ -10,11 +10,6 @@ export enum CP {
gt = 'gt'
}
export const enum IterateDirection {
DEFAULT = 0,
REVERSE = 1
}
export interface IterableWithSize<T> extends Iterable<T> {
size: number | ((...args: any[]) => number);
}
@ -24,3 +19,5 @@ export interface IterableWithLength<T> extends Iterable<T> {
}
export type IterableWithSizeOrLength<T> = IterableWithSize<T> | IterableWithLength<T>
export type BinaryTreePrintOptions = {isShowUndefined?: boolean, isShowNull?: boolean, isShowRedBlackNIL?: boolean}

View file

@ -29,9 +29,5 @@ export type BiTreeDeleteResult<N> = { deleted: N | null | undefined; needBalance
export type BinaryTreeNodeNested<T> = BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type BinaryTreeOptions = { iterationType?: IterationType }
//
// export type BTNIdentifierOrNU<N> = BTNKey | N | null | undefined;
//
// export type BTNIdentifierOrU<N> = BTNKey | N | undefined;
//
// export type BTNOrNU<N> = N | null | undefined;
export type NodeDisplayLayout = [string[], number, number, number];

View file

@ -3,8 +3,8 @@
<head>
<meta charset='UTF-8'>
<title>CDN Test</title>
<script src="../../dist/umd/data-structure-typed.min.js"></script>
<!-- <script src="../../dist/umd/data-structure-typed.js"></script>-->
<!-- <script src="../../dist/umd/data-structure-typed.min.js"></script>-->
<script src="../../dist/umd/data-structure-typed.js"></script>
<!-- <script src='https://cdn.jsdelivr.net/npm/data-structure-typed/dist/umd/data-structure-typed.min.js'></script>-->
<!-- <script src='https://cdn.jsdelivr.net/npm/data-structure-typed@1.42.2/dist/umd/data-structure-typed.min.js'></script>-->
<!-- <script src='https://cdn.jsdelivr.net/npm/data-structure-typed@1.43.3/dist/umd/data-structure-typed.min.js'></script>-->
@ -19,17 +19,18 @@
</ul>
</div>
<script defer>
const $modules = document.querySelector('.modules');
try {
const { Queue } = dataStructureTyped;
const queue = new Queue();
const n = 100000;
const n = 1000000;
const startEn = performance.now();
for (let i = 0; i < n; i++) {
queue.enqueue(i);
}
console.log(`Queue ${n} enqueue `, performance.now() - startEn);
console.log((performance.now() - startEn).toFixed(2), `Queue ${n.toLocaleString()} enqueue `);
let last = 0;
const startTime = performance.now();
@ -37,13 +38,14 @@
last = queue.dequeue();
}
console.log(`Queue ${n} dequeue `, performance.now() - startTime);
console.log((performance.now() - startTime).toFixed(2) ,`Queue ${n.toLocaleString()} dequeue `);
} catch (e) {
console.error(e);
}
try {
const { AVLTree } = window.dataStructureTyped;
const { AVLTree } = dataStructureTyped;
const avlTree = new AVLTree();
const $avlTree = document.createElement('li');
const $avlTreeSpan = document.createElement('span');
@ -52,8 +54,8 @@
for (let i = 1; i < 31; i++) {
avlTree.add(i, i);
}
console.log(avlTree.bfs());
// avlTree.print();
console.log(avlTree.bfs(), `avlTree.bfs()`);
avlTree.print();
$modules.append($avlTree);
} catch (e) {
console.error(e);
@ -66,18 +68,18 @@
tree.add(12);
tree.addMany([1, 6, 9, 8, 5, 2, 3, 4, 7])
tree.add(10);
console.log(tree.isPerfectlyBalanced());
tree.print();
console.log(tree.isPerfectlyBalanced(), `tree.isPerfectlyBalanced()`);
tree.print(undefined, {isShowUndefined: true});
const node3 = tree.getNode(3);
if (node3) node3.right = tree.createNode(1);
console.log(tree.isPerfectlyBalanced());
console.log(tree.isPerfectlyBalanced(), `tree.isPerfectlyBalanced()`);
tree.print();
tree.clear();
tree.addMany([1, null, 2, null, 3, null, 4, null, 5, null, 6, null]);
console.log(tree.isPerfectlyBalanced());
tree.print();
console.log(tree.isPerfectlyBalanced(), `tree.isPerfectlyBalanced()`);
tree.print(undefined, {isShowNull: true});
} catch (e) {
console.error(e);
}
@ -85,26 +87,26 @@
try {
const { OrderedMap } = sdsl;
const { RedBlackTree, AVLTree } = dataStructureTyped;
const { RedBlackTree } = dataStructureTyped;
const cRBTree = new OrderedMap();
const rbTree = new RedBlackTree();
const tS = performance.now();
const n = 100000;
for (let i = 1; i < n; i++) {
for (let i = 0; i < n; i++) {
rbTree.add(i, i);
}
console.log(`RedBlackTree ${n} add`, performance.now() - tS);
console.log(rbTree.size);
console.log(( performance.now() - tS).toFixed(2), `RedBlackTree ${n.toLocaleString()} add`);
console.log(`rbTree.size`, rbTree.size);
for (let i = 0; i < n - 20; i++) {
rbTree.delete(i)
}
rbTree.print(rbTree.root,{isShowRedBlackNIL: true});
const cS = performance.now();
for (let i = 1; i < 100000; i++) {
cRBTree.setElement(i, i);
}
console.log(`CRedBlackTree ${n} add`, performance.now() - cS);
console.log(cRBTree.size());
// console.log(tree.isPerfectlyBalanced());
// tree.print();
console.log((performance.now() - cS).toFixed(2), `CRedBlackTree ${n.toLocaleString()} add`);
console.log(cRBTree.size(), `cRBTree.size()`);
} catch (e) {
console.error(e);
}
@ -123,8 +125,8 @@
for (let i = 0; i < n; i++) {
pq.pop();
}
console.log(`PriorityQueue ${n} add`, performance.now() - tS);
console.log(pq.size);
console.log(( performance.now() - tS).toFixed(2), `PriorityQueue ${n.toLocaleString()} add`);
console.log(pq.size, `pq.size`);
const cS = performance.now();
const cpq = new CPriorityQueue();
@ -135,8 +137,8 @@
for (let i = 0; i < n; i++) {
cpq.pop();
}
console.log(`CPriorityQueue ${n} add`, performance.now() - cS);
console.log(cpq.size());
console.log((performance.now() - cS).toFixed(), `CPriorityQueue ${n.toLocaleString()} add`);
console.log(cpq.size(), `cpq.size()`);
} catch (e) {
console.error(e);
}