1. 程式人生 > >二叉搜索樹的前驅和後繼詳細推導

二叉搜索樹的前驅和後繼詳細推導

right info sta 條件 代碼 圖片 推導 col turn

後繼和前驅

定義:一個結點的後繼,是大於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;
    }
}

基本上是一樣的。

二叉搜索樹的前驅和後繼詳細推導