1. 程式人生 > >二叉搜尋樹(BST)的刪除演算法原理解析

二叉搜尋樹(BST)的刪除演算法原理解析

二叉搜尋樹的刪除演算法主要分兩種情況:

1、要刪除的節點只有一個孩子(左孩子或右孩子),這種情況比較簡單,只需要將該孩子連線到當前節點的父節點即可。

下面重點講講第二種情況:

2、第二種情況便是要刪除的節點有兩個孩子,這個時候的演算法就比較複雜(相比較於只有一個孩子的情況)。首先我們需要找到待刪除節點的左子樹上的最大值節點,或者右子樹上的最小值節點,然後將該節點的引數值與待刪除的節點引數值進行交換,最後刪除該節點,這樣需要刪除的引數就從該二叉樹中刪除了。

對於第二種情況,由於需要進行節點交換,剛接觸的時候,可能會困惑,進行交換之後的二叉樹是否還滿足二叉搜尋樹的結構特點呢?以與左子樹最大節點交換為例,儘管左子樹的根節點比其父節點小,但是左子樹的節點中存在比左子樹的根節點大的節點,這樣如何保證其比右子樹的根節點小呢?比如下面一個BST就不滿足演算法:

                                                             39

                                               30                         44

                                       27            36

                                22          31              45(大於44)

                                                          37

上面的二叉樹乍一看滿足BST的結構特點:左孩子的值小於父親,右孩子的值大於父親

但是如從BST構成的角度,一步一步的分析,就會發現節點45應該在右子樹上。

其實,上述二叉樹(如果是BST)的左子樹的所有節點都應小於39,左子樹節點的最大值也應該在30與39之間,不會存在大於44的情況。

由上討論,便知不存在左子樹最大節點大於右子樹根節點的情況了。(同理也不會存在右子樹最小值大於左子樹根節點的情況)

下面附上一段BST刪除演算法程式碼(源於Clifford A.Shaffer 《date structures and algorithm analysis in C++》):

(此段程式碼的刪除不是簡單意義上的刪除,而是對二叉樹的重構)

//return the root of the updated tree after removal
//t point to the removed node
BinNode<Elem>* removehelp(BinNode<Elem>* subroot, const Elem& e, BinNode<Elem>*& t) {
	if (subroot == NULL) return NULL;
	else if (e < subroot->val())
		subroot->setLeft(removehelp(subroot->left(), e, t));
	else if (e > subroot->val())
		subroot->setRight(removehelp(subroot->right(), e, t));
	else { // Found it: remove it
		BinNode<Elem>* temp;
		t = subroot;
		if (subroot->left() == NULL)
			subroot = subroot->right();
		else if (subroot->right() == NULL)
			subroot = subroot->left();
		else {  // Both children are non-empty
			subroot->setRight(deletemin(subroot->right(), temp));
			Elem te = subroot->val();
			subroot->setVal(temp->val());
			temp->setVal(te);
			t = temp;
		}
	}
	return subroot;
}
//return the root of the tree after remove the node with the minimum value
BinNode<Elem>* deletemin(BinNode<Elem>* subroot, BinNode<Elem>*& min) {
	if (subroot->left() == NULL) {
		min = subroot;
		return subroot->right();
	}
	else { // Continue left
		subroot->setLeft(deletemin(subroot->left(), min));
		return subroot;
	}
}