Skip to content

feat(bst): binary-search-tree implementation #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/tree/BinaryTree.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// import { BinaryTreeNode } from './BinaryTreeNode'

// export class BinaryTree {
// public root: BinaryTreeNode | null

// constructor(value: any) {
// this.root = value ? new BinaryTreeNode(value) : null
// }
// }
18 changes: 18 additions & 0 deletions src/tree/BinaryTreeNode.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { BinaryTreeNode } from './BinaryTreeNode'

describe('BinaryTreeNode', () => {
it('should create an node with passed value', () => {
const btn = new BinaryTreeNode(9)
expect(btn.value).toBe(9)
expect(btn.left).toBe(null)
expect(btn.right).toBe(null)
})

it('should create an node with passed left node & right node', () => {
const leftNode = new BinaryTreeNode(6)
const rightNode = new BinaryTreeNode(12)
const rootNode = new BinaryTreeNode(9, leftNode, rightNode)
expect(rootNode.left).toBe(leftNode)
expect(rootNode.right).toBe(rightNode)
})
})
30 changes: 30 additions & 0 deletions src/tree/BinaryTreeNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* 二叉树指针
*/
export type IBinaryTreeNodePointer = BinaryTreeNode | null

/**
* 二叉树节点
*/
export class BinaryTreeNode {
/** 本节点的值 */
public value: any
/** 本节点的左子节点 */
public left: IBinaryTreeNodePointer
/** 本节点的右子节点 */
public right: IBinaryTreeNodePointer
// /** 指向本节点的父节点,在某些操作中奇效,例如移除root节点的时候 */
// public parent: IBinaryTreeNodePointer

constructor(
value: any,
left: IBinaryTreeNodePointer = null,
right: IBinaryTreeNodePointer = null
// parent: IBinaryTreeNodePointer = null
) {
this.value = value
this.left = left
this.right = right
// this.parent = parent
}
}
9 changes: 9 additions & 0 deletions src/tree/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# 二叉树 (Binary Tree)

## 便利顺序

先序遍历 1.访问根结点; 2.先序遍历左子树; 3.先序遍历右子树。

中序遍历 1.中序遍历左子树; 2.访问根结点; 3.中序遍历右子树。

后序遍历 1.后序遍历左子树; 2.后序遍历右子树; 3.访问根结点。
223 changes: 223 additions & 0 deletions src/tree/binary-search-tree/BinarySearchNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
import { BinaryTreeNode } from '../BinaryTreeNode'

// 用于遍历树节点的回调函数
// 遍历时,回调函数的参数是每个节点的value传递进去的
export type ITraversalCallback = (value: any) => void

export class BinarySearchNode extends BinaryTreeNode {
/**
* 中序遍历
* 左 - 中 - 右
* @param node
* @param callback
*/
public static traversalInOrder(
node: BinarySearchNode | null,
callback: ITraversalCallback
): void {
if (node === null) {
return
} else {
this.traversalInOrder(node.left, callback)
callback(node.value)
this.traversalInOrder(node.right, callback)
}
}

/**
* 先序遍历
* 中 - 左 - 右
* @param node
* @param callback
*/
public static traversalPreviousOrder(
node: BinarySearchNode | null,
callback: ITraversalCallback
): void {
if (node === null) {
return
} else {
callback(node.value)
this.traversalPreviousOrder(node.left, callback)
this.traversalPreviousOrder(node.right, callback)
}
}

/**
* 后序遍历
* 左 - 右 - 中
* @param node
* @param callback
*/
public static traversalPostOrder(
node: BinarySearchNode | null,
callback: ITraversalCallback
): void {
if (node === null) {
return
} else {
this.traversalPostOrder(node.left, callback)
this.traversalPostOrder(node.right, callback)
callback(node.value)
}
}

/**
* 根据value查找value对应的node
* @param node
* @param value
* @returns {BinarySearchNode | null}
*/
public static find(node: BinarySearchNode | null, value: any): BinarySearchNode | null {
if (node === null) {
return null
} else {
if (value < node.value) {
return this.find(node.left, value)
} else if (value > node.value) {
return this.find(node.right, value)
} else {
return node
}
}
}

/**
* 查询是否有value节点
* @param node { BinarySearchNode | null }
* @param value { BinarySearchNode | null }
* @returns {Boolean}
*/
public static search(node: BinarySearchNode | null, value: any): boolean {
if (node === null) {
return false
} else {
// value 比节点 value 小,左侧节点
if (value < node.value) {
return this.search(node.left, value)
}

// value 比节点 value 大,右侧节点
else if (value > node.value) {
return this.search(node.right, value)
}
// value === 节点 value
else {
return true
}
}
}

/**
* 向某个节点下插入新的值
* @param node {BinarySearchNode} 节点
* @param newNode {BinarySearchNode} 要插入的节点
* @returns {void}
*/
public static insertNode(node: BinarySearchNode, newNode: BinarySearchNode) {
if (newNode.value < node.value) {
if (node.left === null) {
// newNode.parent = node;
node.left = newNode
} else {
this.insertNode(node.left, newNode)
}
} else {
if (node.right === null) {
// newNode.parent = node;
node.right = newNode
} else {
this.insertNode(node.right, newNode)
}
}
}

/**
* TODO: 待优化,为了处理好移除根节点(主要是只有一个节点即根节点)的情况,这里采用了返回删除过后的节点树
*
* 移除与value相等的节点
* @param parentNode
* @param node
* @param value
* @returns {BinarySearchNode | null} 被移除节点之后的节点树或者 null
*/
public static removeNode(node: BinarySearchNode | null, value: any): BinarySearchNode | null {
if (node === null) {
return null
}
// 有node,且value在左边
else if (value < node.value) {
node.left = this.removeNode(node.left, value)
return node
}
// 有node,且value在右边
else if (value > node.value) {
node.right = this.removeNode(node.right, value)
return node
}
// 有node,且value等于当前node.value
else {
if (node.left === null && node.right === null) {
node = null
return null
}
if (node.left === null) {
node = node.right
return node
} else if (node.right === null) {
node = node.left
return node
} else {
BinarySearchNode.insertNode(node.right, node.left)
node = node.right
return node
}
}
}

/**
* 查找最小值
* @param node {BinarySearchNode | null}
* @returns {null | any} null 则是root为空的情况,否则返回该最小值
*/
public static findMin(node: BinarySearchNode | null): null | any {
// 此处主要处理root节点为空的情况
if (node === null) {
return null
} else {
// 如果有左子节点,则再次调用本函数
if (node.left) {
return this.findMin(node.left)
}
// 如果没有左子节点,则最小值为当前节点值,直接返回该值
else {
return node.value
}
}
}

/**
* 查找最大值
* @param node {BinarySearchNode | null}
* @returns {null | any} null 则是root为空的情况,否则返回该最大值
*/
public static findMax(node: BinarySearchNode | null): null | any {
// 此处主要处理root节点为空的情况
if (node === null) {
return null
} else {
// 如果有右子节点,则再次调用本函数
if (node.right) {
return this.findMax(node.right)
}
// 如果没有左子节点,则最小值为当前节点值,直接返回该值
else {
return node.value
}
}
}

constructor(value: any) {
super(value)
}
}
9 changes: 9 additions & 0 deletions src/tree/binary-search-tree/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# 二叉搜索树(Binary Search Tree - BST)

## Question

- [Difference between binary tree and binary search tree](https://stackoverflow.com/questions/6380231/difference-between-binary-tree-and-binary-search-tree)

## Resource

- [wikipedia](https://en.wikipedia.org/wiki/Binary_search_tree)
Loading