From 54c74f9af624d611b1cbe6becd4361d36e15c606 Mon Sep 17 00:00:00 2001 From: Revone Date: Tue, 21 Nov 2023 17:30:57 +0800 Subject: [PATCH] feat: The print method supports switches for empty nodes and guardian nodes. refactor: It eliminates some unnecessary type definitions. --- CHANGELOG.md | 2 +- package.json | 8 +- .../binary-tree/binary-tree.ts | 97 ++++++++++++------- src/types/common.ts | 7 +- .../binary-tree/binary-tree.ts | 8 +- test/integration/index.html | 58 +++++------ 6 files changed, 103 insertions(+), 77 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 725a3b2..2b7f62f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/package.json b/package.json index 6c07e38..5d92c9c 100644 --- a/package.json +++ b/package.json @@ -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 ", "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", diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 7a9ed9e..d03887a 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -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 = 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 = 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 = [['─'], 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 [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; diff --git a/src/types/common.ts b/src/types/common.ts index 39f75f1..e0fb3e8 100644 --- a/src/types/common.ts +++ b/src/types/common.ts @@ -10,11 +10,6 @@ export enum CP { gt = 'gt' } -export const enum IterateDirection { - DEFAULT = 0, - REVERSE = 1 -} - export interface IterableWithSize extends Iterable { size: number | ((...args: any[]) => number); } @@ -24,3 +19,5 @@ export interface IterableWithLength extends Iterable { } export type IterableWithSizeOrLength = IterableWithSize | IterableWithLength + +export type BinaryTreePrintOptions = {isShowUndefined?: boolean, isShowNull?: boolean, isShowRedBlackNIL?: boolean} \ No newline at end of file diff --git a/src/types/data-structures/binary-tree/binary-tree.ts b/src/types/data-structures/binary-tree/binary-tree.ts index aaaece0..02ccdcb 100644 --- a/src/types/data-structures/binary-tree/binary-tree.ts +++ b/src/types/data-structures/binary-tree/binary-tree.ts @@ -29,9 +29,5 @@ export type BiTreeDeleteResult = { deleted: N | null | undefined; needBalance export type BinaryTreeNodeNested = BinaryTreeNode>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> export type BinaryTreeOptions = { iterationType?: IterationType } -// -// export type BTNIdentifierOrNU = BTNKey | N | null | undefined; -// -// export type BTNIdentifierOrU = BTNKey | N | undefined; -// -// export type BTNOrNU = N | null | undefined; + +export type NodeDisplayLayout = [string[], number, number, number]; diff --git a/test/integration/index.html b/test/integration/index.html index 28cf505..9bca328 100644 --- a/test/integration/index.html +++ b/test/integration/index.html @@ -3,8 +3,8 @@ CDN Test - - + + @@ -19,17 +19,18 @@