二叉搜索樹的前驅和後繼詳細推導
後繼和前驅
定義:一個結點的後繼,是大於x.key的最小關鍵字的結點。
一個結點的前驅,是小於x.key的最大關鍵字的結點。
思路:找一個結點的前驅或者後繼,無非是在三個區域找。
首先分析前驅:
滿足兩個條件,一是要小於當前鍵值,那麽只有LP和LS區可以找。
二要求是其中最大的值。我們知道,對於LP來說,X、LS、RS都屬於他的右子樹,那麽,X、LS和RS都是大於它的。
所以很顯然,前驅就是LS中的最大值,即前驅 = 左子樹中的最大值。條件是:存在左子樹。
那不存在左子樹只有左父母的情況呢?
那只能在LP上找了,LP也具有兩部分,第一部分是LP的LS,LP的LS雖然滿足小於X的條件,但是LP的LS中所有元素都是小於LP的,所以至少也是LP。
還有一部分,LP可能有左父母或者右父母,顯然,右父母大於他的所有左子樹,包括X,條件一都不滿足,顯然不行。左父母小於LP,所以它競爭不過LP。
所以最終結論就是,在只有左父母,沒有左子樹的情況,前驅 = 左父母的值。
那不存在左子樹和左父母的情況呢?
那就只剩下右子樹和右父母了,顯然,右子樹肯定不行,它的所有元素都大於X。那就只能在右父母中找了,畢竟雖然右父母大於它,但是右父母也有左/右父母和右子樹。
右父母的右父母,和右子樹都不行,都大於右父母本身,更大於X了。那就只能在右父母的左父母上找了,對於左父母來說,他的右子樹全都大於他,即包括X的右父母和X,所以,此時找到的左父母就是我們的前驅。
所以,不存在左子樹和左父母的情況,前驅 = 右父母的左父母(如果右父母不存在左父母,就一直往上遍歷,直至出現左父母)。
分析完畢。下面是代碼實現。
因為我們的二叉樹的結點只有Left和Right指針,所以這題感覺要用遞歸來做,或者棧。下面我們用棧寫一個吧(時間復雜度是O(N))
BinTree Predecessor(BinTree X,BinTree BST) { if(X->Left!=NULL) return FindMax(X->Left); else { Stack S; S = CreatStack(); while(BST!=X) { Push(S,BST);if(X->Data > BST->Data) BST = BST->Right; else if(X->Data < BST->Data) BST = BST->Left; } BinTree Par,Son; Son = X; while((Par = Pop(S))->Right!=Son)Son = Par;//相當於Case2&3結合,直至找到左母親為止。 return Par; } }
插播一個遞歸和棧的區別:
接著分析後繼:(類比前驅,如果前驅看懂了可以不用看,基本上是一樣的分析思路)
滿足兩個條件,一是要大於當前鍵值,那麽只有RP和RS區可以找。
二要求是其中最小的值。我們知道,對於RP來說,X、LS、RS都屬於他的左子樹,那麽,X、LS和RS都是小於它的。
所以很顯然,前驅就是RS中的最小值,即後繼 = 右子樹中的最小值。條件是:存在右子樹。
那不存在右子樹只有右父母的情況呢?
那只能在RP上找了,RP也具有兩部分,第一部分是LP的RS,RP的RS雖然滿足大於X的條件,但是RP的RS中所有元素都是大於LP的,所以找後繼,至少也得是RP。
還有一部分,RP可能有左父母或者右父母,顯然,左父母小於他的所有右子樹,包括X,條件一都不滿足,顯然不行。右父母大於RP,所以它競爭不過RP。
所以最終結論就是,在只有右父母,沒有右子樹的情況,後繼 = 右父母的值。
那不存在右子樹和右父母的情況呢?
那就只剩下左子樹和左父母了,顯然,左子樹肯定不行,它的所有元素都小於X。那就只能在左父母中找了,畢竟雖然左父母小於它,但是右父母也有它本身的左/右父母和左子樹。
左父母的左父母,和左子樹都不行,都小於左父母本身,更小於X了。那就只能在左父母的右父母上找了,對於它的右父母來說,他的左子樹全都小於他,即包括X的左父母和X,所以,此時找到的右父母就是我們的後繼。
所以,不存在右子樹和右父母的情況,後繼 = 左父母的右父母(如果左父母不存在右父母,就一直往上遍歷,直至出現右父母)。
分析完畢。下面是代碼實現,同樣是用棧實現。
BinTree Successor(BinTree X,BinTree BST) { if(X->Right) return FindMin(X->Right); else { Stack S; S = CreatStack(); while(BST!=X) { Push(S,BST); if(X->Data > BST->Data) BST = BST->Right; else if(X->Data < BST->Data) BST = BST->Left; } BinTree Par,Son; Son = X; while((Par = Pop(S))->Left!=Son )Son = Par; return Par; } }
基本上是一樣的。
二叉搜索樹的前驅和後繼詳細推導