二叉搜索樹(Binary Search Tree)爲非線性結構,樹與鏈表同樣爲動態數據結構也可稱二叉搜索樹爲多個鏈表所組成實現的,因爲二叉搜索樹性能比較高因此屬於比較經常使用的數據結構;二叉搜索樹每一個節點除了Key外還存在指向左子樹的Left節點與指向右子樹的Right節點,如左或右子樹不存在則該節點值爲Null;node
二叉搜索樹爲一種特殊的二叉樹,與二叉樹有相似的結構,存在惟一的根節點,每個節點最多隻存在兩個子節點分別爲左子樹與右子樹,當某個節點不存在任何子節點時又稱爲葉子節點,每一個節點有且只有一個父節點,二叉樹具備與生俱來的遞歸結構;
一、 惟一根節點
二、 每一個節點最多隻有兩個節點
三、 葉子節點不存在任何子節點
四、 只有惟一父節點算法
二叉搜索樹與普通二叉樹的根本區別在於二叉搜索樹中任意一個節點的值大於該節點左子樹中任意節點的值,小於該節點右子樹中任意一個節點的值;
一、 節點的左子樹任意一個節點值比當前節點值小
二、 節點的右子樹任意一個節點值比當前節點值大數據結構
因爲二叉搜索樹左右子樹所具備的獨特特性,當使用二叉搜索樹存儲數據時數據的查找將具備很是高的性能,但就是由於該特性因此並不是全部數據均可用二叉搜索樹存儲,能存儲的數據元素必須具有可比較性;性能
一、二叉搜索樹定義
根據二叉搜索樹的特性先定義該數據類型的結構;code
type BST struct { root *TreeNode size int compare Comparable } type TreeNode struct { e interface{} left *TreeNode right *TreeNode }
BST:爲定義的二叉搜索樹自定義對象
TreeNode:爲樹中每一個節點的節點自定義對象
compare:爲定義的用於樹中節點元素進行數據對比的對象
size:二叉搜索樹的元素個數
root:樹的根節點
e:節點元素值
left:左子樹
right:右子樹對象
二、具體二叉搜索樹方法實現blog
/** 元素比較 */ type Comparable func(c1 interface{}, c2 interface{}) int /** 建立二叉樹 */ func NewBST(comparable Comparable) *BST { return &BST{size: 0, root: nil, compare: comparable} } /** 建立節點 */ func newTreeNode(e interface{}) *TreeNode { return &TreeNode{e: e, left: nil, right: nil} } /** 二叉樹大小 */ func (t *BST) Size() int { return t.size } /** 是否未空 */ func (t *BST) IsEmpty() bool { return t.size == 0 } /** 添加元素 */ func (t *BST) Add(e interface{}) { t.root = t.add(t.root, e) } /** 用於遞歸添加元素 */ func (t *BST) add(node *TreeNode, e interface{}) *TreeNode { if node == nil { t.size++ return newTreeNode(e) } if t.compare(e, node.e) < 0 { node.left = t.add(node.left, e) } else if t.compare(e, node.e) > 0 { node.right = t.add(node.right, e) } return node } /** 刪除元素 */ func (t *BST) Remove(e interface{}) { t.root = t.remove(t.root, e) } /** 查找最小節點 */ func (t *BST) Minimum() *TreeNode { return t.minimum(t.root) } func (t *BST) minimum(node *TreeNode) *TreeNode { if node.left == nil { return node } return t.minimum(node.left) } func (t *BST) remove(node *TreeNode, e interface{}) *TreeNode { if node == nil { return nil } //值與當前節點值比較 if t.compare(e, node.e) < 0 { node.left = t.remove(node.left, e) return node } else if t.compare(e, node.e) > 0 { node.right = t.remove(node.right, e) return node } else { // t.compare(e,node.e)==0{ //須要刪除的節點爲當前節點時 if node.left == nil { //右子樹頂上 var rightNode = node.right node.right = nil t.size-- return rightNode } else if node.right == nil { //左子樹頂上 var leftNode = node.left node.left = nil t.size-- return leftNode } //左右節點均不爲空,找到比當前節點大的最小節點(此節點爲右子樹最小節點) //用右子樹最小節點替代須要刪除的當前節點 var successor = t.minimum(node.right) successor.right = t.removeMin(node.right) successor.left = node.left node.left = nil node.right = nil return successor } }
因爲二叉搜索樹所具備的特性,全部不少操做均可用遞歸來實現,好比元素的添加、刪除、查找等等;排序
一、元素添加
二叉搜索樹的元素添加關鍵在於遞歸與元素值的比較,關鍵三點:一、節點爲空建立新節點爲當前節點;二、元素比當前節點小,在左子樹添加;元素比當前節點大,在右子樹添加;遞歸
二、元素刪除
二叉搜索樹的元素刪除關鍵在於刪除節點後調整樹結構已保持樹具有左子樹小於根節點值,右子樹大於跟節點值的特性;rem
元素刪除關鍵點:
一、 小於當前節點在左子樹查找刪除
二、 大於當前節點在右子樹查找刪除
三、 需刪除的節點左子樹不存在,右子樹頂上
四、 需刪除的節點右子樹不存在,左子樹頂上
五、 需刪除節點左右子樹均存在,找到比該節點大的最小節點(右子樹最小節點),用該節點替換須要刪除的節點
因爲二叉搜索樹的特性,經過中序遍歷可獲得排序好的數據,二叉搜索樹的搜索、插入、刪除時間複雜度爲O(log(n)),n爲樹的深度;
參考資料: 《算法四》