[DS] Binary Search Tree
Binary Search Tree 基本概念是每一個節點最多有左右各一個子節點, 左子節點的值小於自身節點的值, 右子節點則大於本身.
A Binary Search Tree (BST) is a binary tree in which each vertex has only up to 2 children that satisfies BST property: All vertices in the left subtree of a vertex must hold a value smaller than its own and all vertices in the right subtree of a vertex must hold a value larger than its own.
只要符合上述定義, 無論樹長得如何, 都符合 BST 的規範.
BST 在搜尋資料上有 O(log N) 複雜度優勢, 是很常使用的基礎資料結構.
Data Struct
一般用資料結構來表示二元樹節點有兩種方式:
w/ parent
struct node {
int value;
node *parent;
node *l_child;
node *r_child;
}
w/o parent
struct node {
int value;
node *l_child;
node *r_child;
}
兩者的差別至在於節點定義中是否包含指向父節點的屬性, 節點間的連結是單向還是雙向關係.
包含父節點的資料結構雙向連結的屬性, 從二元樹中任一節點巡訪, 皆可完整還原完整二元樹的資料. 若有需要, 可以從任何一個節點開始尋訪, 無須每一次都必須從 Root 開始巡訪. 但當修改二元樹中的資料時, 需要注意維護節點中的連結關係, 尤其是父節點的連結.
而不包含父節點的結構中, API 呼叫基本上都必須從 Root 開始巡訪. 但相對修改資料時, 只需要處理子節點的單向連結關係, 程式結構都比較簡單.
兩者各有優缺點, 依實務需求決定. 本篇選用不包括父連結的結構.
- Go
- JavaScript
- TypeScript
- Python
type IBSTNode interface {
search(int) bool
insert(int)
remove(int) IBSTNode
findMin() int
findMax() int
findPredecessor(int) int
findSuccessor(int) int
inorder(*[]int)
}
type BST struct {
root IBSTNode
}
type BSTNode struct {
value int
left *BSTNode
right *BSTNode
}
class BST {
constructor(data) {
this.root = null
if (typeof(data) === 'number') {
this.root = new BSTNode(data)
} else if (Array.isArray(data)) {
this.root = new BSTNode(data[0])
for (let i = 1; i < data.length; i++)
this.insert(data[i])
}
}
}
class BSTNode {
constructor(data) {
this.value = data
this.left = null
this.right = null
}
}
export class BST {
root: BSTNode | null
constructor(data: number | Array<number> | null) {
this.root = null
if (typeof(data) === 'number') {
this.root = new BSTNode(data)
} else if (Array.isArray(data)) {
this.root = new BSTNode(data[0])
for (let i = 1; i < data.length; i++)
this.insert(data[i])
}
}
}
type IBSTNode = BSTNode | null
export class BSTNode {
value: number
left: IBSTNode
right: IBSTNode
constructor(data: number) {
this.value = data
this.left = null
this.right = null
}
}
class BST:
def __init__(self, data):
self._root = None
if isinstance(data, int):
self._root = BSTNode(data)
elif isinstance(data, list):
self._root = BSTNode(data[0])
for i in range(1, len(data), 1):
self.insert(data[i])
class BSTNode:
def __init__(self, data):
self.value = data
self.left = None
self.right = None
ADT Basic Operate
BST (and especially balanced BST like AVL Tree) is an efficient data structure to implement a certain kind of Table (or Map) Abstract Data Type (ADT).
A Table ADT must support at least the following three operations as efficient as possible:
- Search(v) — determine if v exists in the ADT or not,
- Insert(v) — insert v into the ADT,
- Remove(v) — remove v from the ADT.
Search(v)
- Go
- JavaScript
- TypeScript
- Python
func (n *BSTNode) search(val int) bool {
if n == nil { return false }
if n.value > val {
return n.left.search(val)
} else if n.value < val {
return n.right.search(val)
} else {
return true
}
}
// class BSTNode
search(val) {
if (this.value === val)
return true
if (this.value > val)
return this.left === null ? false : this.left.search(val)
else
return this.right === null ? false : this.right.search(val)
}
// class BSTNode
public search(val: number): boolean {
if (this.value === val)
return true
if (this.value > val)
return this.left === null ? false : this.left.search(val)
else
return this.right === null ? false : this.right.search(val)
}
# class BSTNode
def search(self, val):
if self.value == val:
return True
if val < self.value:
return False if self.left == None else self.left.search(val)
else:
return False if self.right == None else self.right.search(val)
Insert(v)
- Go
- JavaScript
- TypeScript
- Python
func (bst *BST) Insert(val int) {
if bst.root == nil { return }
bst.root = bst.root.insert(val)
}
func (n *BSTNode) insert(val int) IBSTNode {
return n.insertHelper(val)
}
func (n *BSTNode) insertHelper(val int) *BSTNode {
if n == nil { return newBSTNode(val) }
if val < n.value { n.left = n.left.insertHelper(val) }
else { n.right = n.right.insertHelper(val) }
return n
}
// class BST
insert(val) {
if (this.root === null) return
this.root = this.root.insert(val)
}
// class BSTNode
insert(val) {
return BSTNode._insertHelper(val, this)
}
static _insertHelper(val, node) {
if (node === null) return new BSTNode(val)
if (val < node.value)
node.left = BSTNode._insertHelper(val, node.left)
else
node.right = BSTNode._insertHelper(val, node.right)
return node
}
// class BST
insert(val: number) {
if (this.root === null) return
this.root = this.root.insert(val)
}
// class BSTNode
public insert(val: number): IBSTNode {
return BSTNode.insertHelper(val, this)
}
static insertHelper(val: number, node: IBSTNode): IBSTNode {
if (node === null) return new BSTNode(val)
if (val < node.value)
node.left = BSTNode.insertHelper(val, node.left)
else
node.right = BSTNode.insertHelper(val, node.right)
return node
}
# class BST
def insert(self, val):
if self._root is None:
self._root = BSTNode(val)
self._root = self._root.insert(val)
# class BSTNode
def insert(self, val):
return BSTNode.insert_helper(val, self)
@classmethod
def insert_helper(cls, val, node):
if node == None:
return BSTNode(val)
if val < node.value:
node.left = BSTNode.insert_helper(val, node.left)
else:
node.right = BSTNode.insert_helper(val, node.right)
return node
Remove(v)
- Go
- JavaScript
- TypeScript
- Python
func (bst *BST) Remove(val int) {
if bst.root == nil { return }
bst.root = bst.root.remove(val)
}
func (n *BSTNode) remove(val int) IBSTNode {
return n.removeHelper(val)
}
func (n *BSTNode) removeHelper(val int) *BSTNode {
if n == nil { return nil }
if n.value > val {
n.left = n.left.removeHelper(val)
} else if n.value < val {
n.right = n.right.removeHelper(val)
} else {
if n.left != nil && n.right != nil {
successor := n.right.findMin()
n.value = successor
n.right = n.right.removeHelper(successor)
} else if n.left != nil {
n = n.left
} else if n.right != nil {
n = n.right
} else {
return nil
}
}
return n
}
// class BST
remove(val) {
if (this.root === null) return
this.root = this.root.remove(val)
}
// class BSTNode
remove(val) {
return BSTNode._removeHelper(val, this)
}
static _removeHelper(val, node) {
if (node === null) return null
if (val < node.value) {
node.left = BSTNode._removeHelper(val, node.left)
} else if (node.value < val) {
node.right = BSTNode._removeHelper(val, node.right)
} else {
if ((node.left === null) && (node.right === null))
return null
else if (node.left === null)
result = node.right
else if (node.right === null)
result = node.left
else {
let successor = node.right.findMin()
node.value = successor
node.right = BSTNode._removeHelper(successor, node.right)
}
}
return node
}
// class BST
remove(val: number) {
if (this.root === null) return
this.root = this.root.remove(val)
}
// class BSTNode
public remove(val: number): IBSTNode {
return BSTNode.removeHelper(val, this)
}
static removeHelper(val: number, node: IBSTNode): IBSTNode {
if (node === null)
return null
if (val < node.value) {
node.left = BSTNode.removeHelper(val, node.left)
} else if (node.value < val) {
node.right = BSTNode.removeHelper(val, node.right)
} else {
if ((node.left === null) && (node.right === null))
return null
else if (node.left === null)
node = node.right
else if (node.right === null)
node = node.left
else {
let successor = node.right.findMin()
node.value = successor
node.right = BSTNode.removeHelper(successor, node.right)
}
}
return node
}
# class BST
def remove(self, val):
if self._root is None:
return
self._root = self._root.remove(val)
# class BSTNode
def remove(self, val):
return BSTNode.remove_helper(val, self)
@classmethod
def remove_helper(cls, val, node):
if node == None:
return None
if val < node.value:
node.left = BSTNode.remove_helper(val, node.left)
elif node.value < val:
node.right = BSTNode.remove_helper(val, node.right)
else:
if node.left == None and node.right == None:
return None
elif node.left == None:
node = node.right
elif node.right == None:
node = node.left
else:
successor = node.right.find_min()
node.value = successor
node.right = BSTNode.remove_helper(successor, node.right)
return node
Find & Travsal
Min / Max
- Go
- JavaScript
- TypeScript
- Python
func (n *BSTNode) findMin() int {
if n.left == nil { return n.value }
else { return n.left.findMin() }
}
func (n *BSTNode) findMax() int {
if n.right == nil { return n.value }
else { return n.right.findMax() }
}
findMin() {
return this.left === null ? this.value : this.left.findMin()
}
findMax() {
return this.right === null ? this.value : this.right.findMax()
}
public findMin(): number {
return this.left === null ? this.value : this.left.findMin()
}
public findMax(): number {
return this.right === null ? this.value : this.right.findMax()
}
def find_min(self):
return self.value if self.left == None else self.left.find_min()
def find_max(self):
return self.value if self.right == None else self.right.find_max()-
Predecessor
- Go
- JavaScript
- TypeScript
- Python
func (n *BSTNode) findPredecessor(val int) int {
predecessor := NOTFOUND
node := n
for node != nil && node.value != val {
if node.value < val {
predecessor = node.value
node = node.right
} else { node = node.left }
}
if node == nil { return NOTFOUND }
if node.left != nil { return node.left.findMax() }
else { return predecessor }
}
findPredecessor(val) {
let predecessor = NOT_FOUND
let node = this
while ((node !== null) && (node.value !== val)) {
if (node.value < val) {
predecessor = node.value
node = node.right
} else
node = node.left
}
if (node === null)
return NOT_FOUND
if (node.left !== null)
return node.left.findMax()
else
return predecessor
}