UNPKG

pisces-data-structure

Version:

300 lines (222 loc) 8.8 kB
/** * 二叉搜索树 */ import type { IBinarySearchTreeNode, IBinarySearchTree } from "../../../types"; import { SinglyQueue } from "../../index"; class BinarySearchTreeNode<T = any> implements IBinarySearchTreeNode<T> { value: T; left: IBinarySearchTreeNode<T> | null = null; right: IBinarySearchTreeNode<T> | null = null; parent: IBinarySearchTreeNode<T> | null = null; get isLeftChild(): boolean { return !!(this.parent && this.parent.left === this); } get isRightChild(): boolean { return !!(this.parent && this.parent.right === this); } constructor(value: T) { this.value = value; } } class BinarySearchTree<T = any> implements IBinarySearchTree<T> { protected root: IBinarySearchTreeNode<T> | null = null; private insertNode(currentNode: IBinarySearchTreeNode<T>, newNode: IBinarySearchTreeNode<T>) { if (newNode.value < currentNode.value) { if (currentNode.left) { this.insertNode(currentNode.left, newNode); } else { currentNode.left = newNode; newNode.parent = currentNode; } } else { if (currentNode.right) { this.insertNode(currentNode.right, newNode); } else { currentNode.right = newNode; newNode.parent = currentNode; } } } private locateTargetNode(targetValue: T): IBinarySearchTreeNode<T> | null { let _current = this.root; let _parent: IBinarySearchTreeNode<T> | null = null; while (_current) { if (_current.value === targetValue) return _current; _parent = _current; if (_current.value < targetValue) { _current = _current.right; } else { _current = _current.left; } if (_current) { _current.parent = _parent; } } return null; } private findSuccessorTreeNode(delNode: IBinarySearchTreeNode<T>): IBinarySearchTreeNode<T> { let _current = delNode.right; let _successor: IBinarySearchTreeNode<T> | null = null; while (_current) { _successor = _current; _current = _current.left; if (_current) _current.parent = _successor; } if (_successor !== delNode.right) { _successor!.parent!.left = _successor!.right; if (_successor?.right) { _successor.right.parent = _successor.parent; } } else { delNode.right = _successor!.right; if (_successor!.right) { _successor!.right.parent = delNode; } } return _successor!; } protected createTreeNode(value: T): BinarySearchTreeNode<T> { return new BinarySearchTreeNode(value); } protected checkBalance(treeNode: BinarySearchTreeNode<T>, actionType = 'insert') { } insert(value: T) { const newBSTNode = this.createTreeNode(value); if (!this.root) { this.root = newBSTNode; } else { this.insertNode(this.root, newBSTNode); } this.checkBalance(newBSTNode); } preOrderTraverse(callbackFn?: (treeNodeValue: IBinarySearchTreeNode<T>) => void) { const _treeNodeStack: IBinarySearchTreeNode<T>[] = []; let _current: IBinarySearchTreeNode<T> | null = this.root; while (_current !== null || _treeNodeStack.length !== 0) { while (_current !== null) { callbackFn && callbackFn(_current); _treeNodeStack.push(_current); _current = _current.left; } _current = _treeNodeStack.pop()!; _current = _current.right; } } inOrderTraverse(callbackFn?: (treeNodeValue: IBinarySearchTreeNode<T>) => void) { const _treeNodeStack: IBinarySearchTreeNode<T>[] = []; let _current: IBinarySearchTreeNode<T> | null = this.root; while (_current !== null || _treeNodeStack.length !== 0) { while (_current !== null) { _treeNodeStack.push(_current); _current = _current.left; } _current = _treeNodeStack.pop()!; callbackFn && callbackFn(_current); _current = _current.right; } } postOrderTraverse(callbackFn?: (treeNodeValue: IBinarySearchTreeNode<T>) => void) { const _treeNodeStack: IBinarySearchTreeNode<T>[] = []; let _current: IBinarySearchTreeNode<T> | null = this.root; let _lastVisitedTreeNode: IBinarySearchTreeNode<T> | null = null; while (_current !== null || _treeNodeStack.length !== 0) { while (_current !== null) { _treeNodeStack.push(_current); _current = _current.left; } _current = _treeNodeStack[_treeNodeStack.length - 1]; if (_current.right === null || _current.right === _lastVisitedTreeNode) { callbackFn && callbackFn(_current); _lastVisitedTreeNode = _current; _treeNodeStack.pop(); _current = null; } else { _current = _current.right; } } } levelOrderTraverse(callbackFn?: (treeNodeValue: IBinarySearchTreeNode<T>) => void) { if (!this.root) { console.info('[levelOrderTraverse] 二叉树结构为空,层序遍历停止'); } else { const _treeNodeQueue = new SinglyQueue<IBinarySearchTreeNode<T>>(); _treeNodeQueue.enqueue(this.root); while (_treeNodeQueue.size !== 0) { const _frontTreeNode = _treeNodeQueue.dequeue()!; callbackFn && callbackFn(_frontTreeNode); _frontTreeNode.left && _treeNodeQueue.enqueue(_frontTreeNode.left); _frontTreeNode.right && _treeNodeQueue.enqueue(_frontTreeNode.right); } } } findMax(): T | null { if (!this.root) { console.warn('[findMax] 二叉搜索树为空,不存在最值'); return null; } else { let _maxTreeNode = this.root; while (_maxTreeNode.right) { _maxTreeNode = _maxTreeNode.right; } return _maxTreeNode.value; } } findMin(): T | null { if (!this.root) { console.warn('[findMax] 二叉搜索树为空,不存在最值'); return null; } else { let _maxTreeNode = this.root; while (_maxTreeNode.left) { _maxTreeNode = _maxTreeNode.left; } return _maxTreeNode.value; } } search(value: T): boolean { let _current = this.root; while (_current) { if (_current.value === value) { return true; } else if (_current.value < value) { _current = _current.right; } else { _current = _current.left; } } return false; } remove(value: T): boolean { const _current = this.locateTargetNode(value); if (!_current) return false; let _deletedTreeNode: BinarySearchTreeNode<T> = _current; let _replaceNode: IBinarySearchTreeNode<T> | null = null; if (_current.left === null && _current.right === null) { _replaceNode = null; } else if (_current.right === null) { _replaceNode = _current.left; } else if (_current.left === null) { _replaceNode = _current.right; } else { const _successor = this.findSuccessorTreeNode(_current) _current.value = _successor.value; _deletedTreeNode = _successor; _replaceNode = _current; } if (_current === this.root) { this.root = _replaceNode; } else if (_current.isLeftChild) { _current.parent!.left = _replaceNode; } else { _current.parent!.right = _replaceNode; } if (_replaceNode) { _replaceNode.parent = _deletedTreeNode.parent; } this.checkBalance(_deletedTreeNode, 'remove'); return true; } } export { BinarySearchTreeNode, BinarySearchTree, };