徹底弄懂二叉排序樹

2021-08-04 20:13:13 字數 3405 閱讀 6317

在之前學習資料結構的時候,就學過二叉排序樹,不過,由於但是只是紙上談兵,雖然知道二叉排序樹的插入,刪除等的操作過程,不過由於沒有具體實現過,所以當想要實現的時候,就出現了「道理都懂,卻無法做到」的尷尬局面,趁著最近有空,抽了個時間認真學習二叉排序樹,並且手動編寫了實現的**,真正理解了二叉排序樹的操作過程

二叉排序樹,二叉樹的乙個變種,主要的特點在於,該樹的值在分布的時候具有非常明顯的特徵,左子樹的值小於根節點的值,而根節點的值小於右子樹的值,這在進行搜尋,查詢的時候是非常有利的,因為它的平均操作時間接近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 ...