二叉搜索树的三种写法

254 阅读2分钟

孔乙己说茴香豆的茴有四种写法, 这篇文章要讲二叉搜索树的三种写法

image.png 二叉搜索树可高效查找, 时间复杂度是O(logn)

每个节点的元素必须是可比较的

abstract class Comparable<T> {
	abstract compareTo(e: Comparable<T>): number
}

每个节点都有当前元素和左右子节点

class Node<T> {
	public e: T
	public left: Node<T> | null
	public right: Node<T> | null

	constructor(e: T) {
		this.e = e
		this.left = null
		this.right = null
	}
}

使用递归实现二叉搜索树

class BST<T extends Comparable<T>> {
	private root: Node<T> | null
	private _size: number

	constructor() {
		this.root = null
		this._size = 0
	}

	public get size(): number {
		return this._size
	}

	public get isEmpty(): boolean {
		return this._size === 0
	}

	public add(e: T): void {
		if (this.root === null) {
			this.root = new Node(e)
			++this._size
		} else {
			this._addHelper(this.root, e)
		}
	}

	private _addHelper(curRoot: Node<T>, e: T) {
		if (e.compareTo(curRoot.e) < 0) {
			if (curRoot.left === null) {
				curRoot.left = new Node(e)
				++this._size
			} else {
				this._addHelper(curRoot.left, e)
			}
		} else if (e.compareTo(curRoot.e) > 0) {
			if (curRoot.right === null) {
				curRoot.right = new Node(e)
				++this._size
			} else {
				this._addHelper(curRoot.right, e)
			}
		}
	}
}

优化递归实现二叉搜索树

上面写法里冗余的判断节点是否为空, 下面的写法可以优雅的规避

class BST<T extends Comparable<T>> {
	private root: Node<T> | null
	private _size: number

	constructor() {
		this.root = null
		this._size = 0
	}

	public get size(): number {
		return this._size
	}

	public get isEmpty(): boolean {
		return this._size === 0
	}

	public add(e: T): void {
		this.root = this._addHelper(this.root, e)
	}

	private _addHelper(curRoot: Node<T> | null, e: T): Node<T> | null {
		if (curRoot === null) {
			curRoot = new Node(e)
			++this._size
		} else {
			if (e.compareTo(curRoot.e) < 0) {
				curRoot.left = this._addHelper(curRoot.left, e)
			} else if (e.compareTo(curRoot.e) > 0) {
				curRoot.right = this._addHelper(curRoot.right, e)
			}
		}
		return curRoot
	}
}

使用循环实现二叉搜索树

递归是有额外的内存开销的, 下面的写法用循环来添加元素

class BST<T extends Comparable<T>> {
	private root: Node<T> | null
	private _size: number

	constructor() {
		this.root = null
		this._size = 0
	}

	public get size(): number {
		return this._size
	}

	public get isEmpty(): boolean {
		return this._size === 0
	}

	public add(e: T): void {
		if (this.root === null) {
			this.root = new Node(e)
			++this._size
		} else {
			let currentNode = this.root
			while (currentNode) {
				if (e.compareTo(currentNode.e) < 0) {
					if (currentNode.left === null) {
						currentNode.left = new Node(e)
						++this._size
						break
					} else {
						currentNode = currentNode.left
					}
				} else if (e.compareTo(currentNode.e) > 0) {
					if (currentNode.right === null) {
						currentNode.right = new Node(e)
						++this._size
						break
					} else {
						currentNode = currentNode.right
					}
				}
			}
		}
	}
}

测试用例

const bst = new BST()

class TestNode<T> implements Comparable<T> {
	public value: number
	constructor(val: number) {
		this.value = val
	}

	compareTo(e: TestNode<T>): number {
		return this.value - e.value
	}
}

;[5, 2, 6, 7, 1, 9, 4, 3, 8, 10]
	.map((item) => {
		return new TestNode(item)
	})
	.forEach((item) => {
		bst.add(item)
	})

console.warn('bst', JSON.stringify(bst, null, 4))

// 输出
bst {
    "root": {
        "e": {
            "value": 5
        },
        "left": {
            "e": {
                "value": 2
            },
            "left": {
                "e": {
                    "value": 1
                },
                "left": null,
                "right": null
            },
            "right": {
                "e": {
                    "value": 4
                },
                "left": {
                    "e": {
                        "value": 3
                    },
                    "left": null,
                    "right": null
                },
                "right": null
            }
        },
        "right": {
            "e": {
                "value": 6
            },
            "left": null,
            "right": {
                "e": {
                    "value": 7
                },
                "left": null,
                "right": {
                    "e": {
                        "value": 9
                    },
                    "left": {
                        "e": {
                            "value": 8
                        },
                        "left": null,
                        "right": null
                    },
                    "right": {
                        "e": {
                            "value": 10
                        },
                        "left": null,
                        "right": null
                    }
                }
            }
        }
    },
    "_size": 10
}