二叉搜索樹:一棵二叉搜索樹是以一棵二叉樹來組織的,這樣一棵樹能夠使用鏈表的數據結構來表示(也能夠採用數組來實現)。除了key和可能帶有的其餘數據外,每一個節點還包含Left,Right,Parent,它們分別指節點的左孩子,右孩子,和父節點。java
一個二叉搜索樹老是知足 :node.left.key<node.key<=node.right.key。node
如下是一個用java實現的二叉搜索樹,包含了查找最大值,最小值,查找某一節點,插入和刪除操做。算法
接下來經過代碼來分析二叉搜索樹中的思想:在代碼實現二叉搜索樹中,大量採用了遞歸的思想,一樣能夠採用循環去遞歸來實現。數組
插入:自根節點起遞歸調用「尋找合適位置方法」,使二叉搜索樹始終知足條件 node.left.key<node.key<=node.right.key。數據結構
查詢:自根節點起遞歸調用「查找孩子的方法」。查找孩子的方法採用的思想是,判斷node.key==key 返回,node.key>key 遞歸查找左子樹,node.key<=key 遞歸查 找右子樹。this
查詢最小值:遞歸查找左孩子,直到最後一個左孩子。spa
查詢最大值:遞歸查找右孩子,直到最後一個右孩子。blog
遍歷:遞歸
前序遍歷:根的關鍵字輸出在左右子樹的關鍵字以前。根 左 右。class
中序遍歷:根的關鍵字輸出在左右子樹的關鍵字之間。左 根 右。
後序遍歷:根的關鍵字輸出在左右子樹的關鍵字以後。左 右 根。
刪除:刪除一棵搜索樹是比較麻煩的。共有如下4種狀況
1.刪除節點沒有孩子,直接斷開鏈接便可
2.a圖:刪除節點沒有左孩子,將右孩子移至刪除節點處
3.b圖:刪除節點沒有右孩子,將左孩子移至刪除節點處
4.c圖:有左右孩子,右孩子 沒有 左孩子,將右孩子移動至刪除節點處,將左孩子的父節點鏈接值右孩子。
5.d圖:有左右孩子,且右孩子也有左右孩子,則查找右孩子的最小節點,將最小節點移至刪除節點處。
public class SearchTree {
//樹的根節點
private Node Root = null;
//內部類,結點
private class Node{
Node parent;//父節點
Node Left;//左孩子
Node Right;//右孩子
int keyValue;//關鍵字
public Node(Node parent,
Node Left,
Node Right,
int keyValue) {
this.parent = parent;
this.Left = Left;
this.Right = Right;
this.keyValue = keyValue;
}
}
public void delete(int value) {
Node deleteNode = this.search(value);//查找刪除節點
if(deleteNode.Left==null) {//沒有左孩子
transplant(deleteNode, deleteNode.Right);
}else if(deleteNode.Right==null) {//沒有右孩子
transplant(deleteNode, deleteNode.Left);
}else {//有左右孩子時
Node min = this.min(deleteNode.Right);//查找右孩子的最小節點
if(min.parent!=deleteNode) {
transplant(min, min.Right);
min.Right = deleteNode.Right;
min.Right.parent = min;
}
transplant(deleteNode, min);
min.Left = deleteNode.Left;
min.Left.parent = min;
}
}
//交換子樹,將node2 移動至node1的位置。
private void transplant(Node node1,Node node2) {
if(node1.parent==null) {
this.Root = node2;
}else if(node1==node1.parent.Left) {
node1.parent.Left = node2;
}else {
node1.parent.Right= node2;
}
if(node2!=null) {
node2.parent = node1.parent;
}
}
//查找方法
public Node search(int value) {
return searchNode(this.Root,value);
}
private Node searchNode(Node node,int key) {
if(node==null || node.keyValue==key) {
return node;
}
if(node.keyValue>key) {
return this.searchNode(node.Left,key);
}else {
return this.searchNode(node.Right, key);
}
}
//插入方法
public void insert(int value) {
Node child = new Node(null, null, null, value);
findRightPlace(this.Root,child);
}
private void findRightPlace(Node currentRoot,Node insertNode) {
if(currentRoot!=null) {
if(currentRoot.keyValue>insertNode.keyValue) {
if(currentRoot.Left==null) {
currentRoot.Left = insertNode;
insertNode.parent = currentRoot;
}else {
findRightPlace(currentRoot.Left,insertNode);
}
}else {
if(currentRoot.Right==null) {
currentRoot.Right = insertNode;
insertNode.parent = currentRoot;
}else {
findRightPlace(currentRoot.Right,insertNode);
}
}
}else {
this.Root = insertNode;
}
}
//查找最大
public int findMax() {
return max(this.Root)==null?-1:max(this.Root).keyValue;
}
private Node max(Node node) {
if(node!=null) {
if(node.Right!=null) {
return max(node.Right);
}else {
return node;
}
}else {
return null;
}
}
//查找最小
public int findMin() {
return min(this.Root)==null?-1:min(this.Root).keyValue;
}
private Node min(Node node) {
if(node!=null) {
if(node.Left!=null) {
return min(node.Left);
}else {
return node;
}
}else {
return null;
}
}
//後序遍歷
public void after() {
afterShow(this.Root);
}
private void afterShow(Node node) {
if(node!=null) {
afterShow(node.Left);
afterShow(node.Right);
System.out.println(node.keyValue);
}
}
//中序遍歷
public void mid() {
midShow(this.Root);
}
private void midShow(Node node) {
if(node!=null) {
midShow(node.Left);
System.out.println(node.keyValue);
midShow(node.Right);
}
}
//前序遍歷
public void ahead() {
aheadShow(this.Root);
}
private void aheadShow(Node node) {
if(node!=null) {
System.out.println(node.keyValue);
aheadShow(node.Left);
aheadShow(node.Right);
}
}
參考資料 《算法導論》第三版