在之前學習資料結構的時候,就學過二叉排序樹,不過,由於但是只是紙上談兵,雖然知道二叉排序樹的插入,刪除等的操作過程,不過由於沒有具體實現過,所以當想要實現的時候,就出現了「道理都懂,卻無法做到」的尷尬局面,趁著最近有空,抽了個時間認真學習二叉排序樹,並且手動編寫了實現的**,真正理解了二叉排序樹的操作過程
二叉排序樹,二叉樹的乙個變種,主要的特點在於,該樹的值在分布的時候具有非常明顯的特徵,左子樹的值小於根節點的值,而根節點的值小於右子樹的值,這在進行搜尋,查詢的時候是非常有利的,因為它的平均操作時間接近o(h),h為樹的高度,而且,二叉排序樹本身是具有動態性的,可以動態地進行節點的刪除,插入等的操作,接下來我們就通過具體的例子來學習二叉排序樹
首先先構造乙個二叉排序樹,然後我們來通過**演示如何生成該樹
從圖中可以看到,生成的樹相對是比較平衡的
樹的生成過程
class tree
// 構造樹,構造的過程相當於將data中的資料插入
public void construct(int data)
}/**
* 插入節點
* @param value 節點的值
*/public void insert(int value)else
}current = new node(value, pre, null, null);
// 如果pre是null,說明此時是空樹
if (pre == null)else else }}
/*** 中序遍歷樹,可以用於校驗樹是否成功建立
* @param current 當前節點
*/public void show(node current)
}/**
* 樹的節點
*/private class node}}
經過上面的步驟,我們就成功的建立了乙個二叉排序樹了,可以通過簡單的測試來判斷樹的建立是否正確,其中乙個比較簡單的方法就是通過中序遍歷該樹,由於二叉排序樹的特點,中序遍歷的結果應當是一系列從小到大排序好的值
獲取樹中的最小值以及最大值
由於二叉排序樹的特點,其最小值必定在最左子樹,最大值必然在最右子樹,當然,如果是空樹那就沒有了,如果是只有跟節點的樹,那麼最小值以及最大值都是根節點本身
// 獲取樹中的最小值
public integer getmin()
// 尋找最左子樹
while (current.left != null)
return current.value;
}// 獲取樹中的最大值
public integer getmax()
// 尋找最右子樹
while (current.right != null)
return current.value;
}
查詢包含某一值的節點
// 查詢包含某一值的節點
public node search(int value)else if (current.value < value)else
}// 找不到則返回null
return null;
}
查詢某乙個節點的前驅和後繼
根據二叉排序樹的特點,某乙個節點的前驅只可能是
根據二叉排序樹的特點,如果target.parent.left == target,則target.parent的值比target的值大,所以應該一直往上尋找,如果紅色箭頭所示,當找到第乙個target.parent.right == target,如果黑色方框所示,這意味著target.parent的值是剛剛所經過的路徑的最小值,而target就是倒數第二小的值,(還記得,target.parent的右子樹的最左子樹嗎?)
後繼節點的查詢類似,只不過方向應該相反,這裡就不重複敘述了
// 前驅
public node getpre(node target)
// 如果左子樹非空,則前驅為左子樹的最右子樹
if (target.left != null)
return target;
}else
return parent;}}
// 後繼
public node getsuc(node target)
// 查詢右子樹的最左子樹
if (target.right != null)
return target;
}else
return parent;}}
刪除節點
刪除節點是二叉排序樹最複雜的乙個地方,主要是由於刪除的時候,存在多種情況
前三種情況比較好處理,直接令其父親指向其孩子即可,最後一種比較複雜,直接看**結合注釋比較好理解
// 刪除節點
public void remove(node target)
// 只有右子樹
if (target.left == null)else
// 如果右孩子非空,右孩子的parent指向target.parent
if (target.right != null)
// 如果target的右子樹為空,而且此時左子樹不為空
// 操作基本同上
}else if (target.right == null)else
target.left.parent = target.parent;
// 如果左右子樹都非空,則用右子樹的最左子樹進行替代
}else else
// 指向target的parent
target.right.parent = target.parent;
// 接管target的左子樹
target.right.left = target.left;
}else
// 直接替換其值即可
current.value = target.value;
// 此時target為右子樹的最左子樹,但是target可能有右子樹
// 所以刪除只有,target.parent.left需要接管target的右子樹
target.parent.left = target.right;}}
}
本小節主要學習了二叉排序樹的基本原理,並且通過**的方式,學習了二叉排序樹的建立,插入,查詢最大值,查詢最小值,查詢指定值的節點,查詢指定節點的前驅,後繼,刪除節點等,其中刪除節點可以說最複雜,也是最難理解的乙個,在學習的過程中最好結合具體的,然後手動演示整個過 二叉排序樹
在複習資料結構,把這個東西總結一下。這種結構是動態查詢表,這種動態是相對靜態查詢 順序查詢,折半查詢,分塊查詢等 來說的。對於各種靜態鍊錶,要達到查詢複雜度為o logn 必須要求有序 而要使插入刪除複雜度為o 1 必須是鍊錶儲存。動態查詢表就可以同時滿足這兩者。動態查詢表的特點是表結構本身在查詢過...
二叉排序樹
name 二叉排序樹相關操作 author unimen date 2011 10 8 13 14 21 刪除結點比較麻煩,總結如下 4大種情況 1 結點p無右孩子 將該點的左孩子變為其在雙親中的同位孩子 1 p為其雙親的左孩子時將其的左孩子變為雙親的左孩子 2 p為其雙親的右孩子時將其的左孩子變為...
二叉排序樹
include include include include struct tree node void insert node struct tree node int void pre order struct tree node void in order struct tree node ...