1. 程式人生 > >二叉排序樹 分析、梳理、程式碼總結

二叉排序樹 分析、梳理、程式碼總結

二叉排序樹(binary sort tree)

二叉排序樹的定義

    二叉排序樹或是一棵空樹,或是具有如下性質的非空二叉樹:

      (1)若它的左子樹非空,則其左子樹所有結點的關鍵字值均小於其根結點的關鍵字值

      (2)若它的右子樹非空,則其右子樹所有結點的關鍵字值均大於其根結點的關鍵字值

      (3)它的左右子樹也分別為一棵二叉排序樹

二叉排序樹的重要特徵:對二叉排序樹進行中序遍歷可以得到一個關鍵字有序的序列

二叉排序樹的儲存:二叉連結串列

/*二叉排序樹的二叉連結串列儲存結構*/
typedef struct BTNode{
    Elemtype key;                       /*記錄的關鍵字,忽略記錄的其他資料項*/
    struct BTNode *lchild,*rchild;  
}BTNode,*BSTree;

二叉排序樹的查詢:

    二叉排序樹不空的時候,將給定值key和結點的關鍵字比較,相等查詢成功,小於查詢左子樹,大於查詢右子樹,返回空查詢失敗。

    查詢過程實際上是從根結點到結點的路徑,即該層的深度。

/*二叉排序樹的查詢*/
BTNode *SearchBST(BSTree T,int key)      /*T指向二叉排序樹的根結點*/
{
    if(T==NULL)                     /*空樹,查詢失敗*/
        return NULL;
    if(key==T->key)             /*查詢成功*/
        return T;
    if(key<T->key)
        return SearchBST(T->lchild,key);        /*查詢左子樹*/
    if(key>T->key)
        return SearchBST(T->rchild,key);       /*查詢右子樹*/
}

二叉排序樹的插入

    插入結點的條件:查詢不成功

    基本思想:(1)若二叉排序樹為空,則新結點作為二叉排序樹的根結點

                     (2)若給定結點的關鍵字的值小於根結點的值,插入到左子樹中

                     (3)若給定結點的關鍵字的值大於根結點的值,插入到右子樹中

/*二叉排序樹的插入*/
BSTree InsertBST_key(BSTree T,int key)
{/*在以T為根結點的二叉排序樹上查詢關鍵字為key的記錄,若不存在將其插入*/
    BTNode *s=SearchBST(T,key);
    if(s!=NULL)
    {
        printf("\n關鍵字%d已存在!\n",s->key);
        return T;
    }
    s=(BTNode *)malloc(sizeof(BTNode));         /*生成一個結點空間*/
    if(s==NULL)
        printf("Error\n");
    s->key=key;
    s->lchild=s->rchild=NULL;
    T=InsertBST(T,s);               /*在二叉排序樹上插入該結點*/
    return T;
}

/*在二叉排序樹上插入一個結點*/
BSTree InsertBST(BSTree T,BTNode *s)
{  /*在以T為根的二叉樹上插入一個指標s所指向的結點並返回根指標T*/
    if(T==NULL)         /*如果T是空樹,則新插入的結點S作為新的樹根*/
        T=s;
    else
    {
        if(s->key<T->key)
            T->lchild=InsertBST(T->lchild,s);       /*遞迴插到T的左子樹中*/
        if(s->key>T->key)
            T->lchild=InsertBST(T->lchild,s);        /*遞迴插到T的右子樹中*/
    }
    return T;
}

二叉排序樹的建立

    二叉樹的建立過程實際上就是一個查詢插入的過程,每次插入的新結點都是二叉樹上新的葉子結點,操作時不必像靜態查詢移動其他結點,只需改動新葉子結點的父結點的左或右指標,由空變為非空即可。二叉排序樹既擁有類似折半查詢的特性,又採用連結串列作為儲存結構。

/*二叉排序樹的建立*/
BSTree CreateBST()      /*由空樹開始,輸入關鍵字序列,建立一棵二叉排序樹*/
{
    BSTree T=NULL,s=NULL;
    int key;
    printf("輸入關鍵字序列,輸入-1結束\n");
    while(1)
    {
        scanf("%d",&key);     
        if(key==-1)
            break;
        s=(BTNode *)malloc(sizeof(BTNode));         /*生成一個結點空間*/
        s->key=key;
        s->lchild=s->rchild=NULL;
        T=InsertBST(T,s);                   /*在二叉排序樹中插入該結點*/
    }
    return T;
}

二叉排序樹的刪除

    假設待刪除的結點為*p,f指向結點*p的雙親,s指向*p的左子樹中關鍵字值最大的結點,q指向s的雙親

    刪除分為3中情況:

      (1)*p為葉子結點,即其左右結點為空-----將其雙親結點f的lchild或rchild置空,刪除結點

      (2)*p只有一棵非空子樹(左子樹或右子樹)

           只有左子樹-----用左子樹的根結點取代要刪除的結點

           只有右子樹-----用右子樹的根結點取代要刪除的結點

      (3)*p左右子樹均非空-----用*p左子樹中關鍵字最大的結點*s替代*p,若*s有左孩子,將左孩子作為*s的雙親結點*q的右孩子  

                                             

    為了刪除結點後重接子樹,要修改查詢演算法

/*為了刪除操作而修改的二叉排序樹查詢*/
BTNode *SearchBST_F(BSTree T,int key,BSTree *F)
{   /*T指向根結點,*F儲存指向key的雙親的指標*/
    /*查詢成功,返回指向key的記錄指標,查詢失敗返回NULL*/
    if(T==NULL)
        return NULL;
    if(key==T->key)
        return T;
    *F=T;
    if(key<T->key)
        return SearchBST_F(T->lchild,key,F);
    if(key>T->key)
        return SearchBST_F(T->rchild,key,F);
}

/*在二叉排序樹中查詢並刪除關鍵字為key的記錄*/
BSTree SearchDeleteBST(BSTree T,int key)
{
        BTNode *f=NULL,*pNULL;
        p=SearchBST_F(T,key,&f);        /*查詢key,p指向key,f指向雙親*/
        if(p!=NULL)
            T=DeleteBST(T,p,f);
        else
            printf("關鍵字為key的記錄不存在!\n");
        return T;
}

二叉排序樹的刪除演算法

/*二叉排序樹的刪除*/
BSTree DeleteBST(BSTree T,BTNode *p,BTNode *f)
{/*刪除p指標指向的結點,f指向*p的雙親結點*/
 /*T是指向根結點的指標*/
    BTNode *par,*s;
    int kind;
    if(p->lchild==NULL&&p->rchild==NULL)            /*情況1,*p為葉子結點*/
        kind=1;                                                 
    else if(p->rchild==NULL)                /*情況2,*p只有左子樹*/
        kind=2; 
    else if(p->lchild==NULL)                /*情況3,*p只有右子樹*/
        kind=3;
    else                                                    /*情況4,*p左右子樹非空*/
        kind=4;
    switch(kind)
    {
        case 1:    if(f==NULL)         /*p指向根結點,樹中只有根結點*/
                                T=NULL;             /*刪除結點*p,T變空樹*/
                        else
                        {
                                if(f->lchild==p)       /* *p是*f的左孩子*/
                                    f->lchild=NULL;
                                else                           /* *p是*f的右孩子*/
                                    f->rchild==NULL;       
                        }
                        free(p);                       /*刪除結點釋放空間*/
                        break;
        case 2:    if(f==NULL)          /*f為NULL,*p為根結點,且只有左子樹*/
                                T=p->lchild;
                        else
                        {
                            if(f->lchild==p)       /* *p是*f的左子樹*/
                                f->lchild=p->lchild;
                            else                         /* *p是*f的右子樹*/
                                f->rchild=p->lchild;
                        }
                        free(p);                       /*刪除結點釋放空間*/
                        break;
        case 3:     if(f==NULL)        /*f為NULL,*p為根結點,且只有左子樹*/
                                T=p->rchild;
                           else
                           {
                               if(p==f->lchild)
                                    f->lchild=p->rchild;
                               else
                                    f->rchild=p->rchild;
                           }
                           free(p);
                           break;
        case 4:     par=p;
                          s=p->lchild;
                          while(s->rchild!=NULL)        /*找到p左子樹的關鍵字最大(最右下)的結點*/
                          {
                              par=s;
                              s=s->rchild;
                          }
                          p->key=s->key;        /*s結點的值覆蓋p結點的值*/
                          if(par==p)           /*處理特殊情況,*p的左孩子為*s*/
                                par->lchild=s->lchild;
                          else
                                par->rchild=s->lchild;      /*s的左子樹連線到s的雙親結點作為雙親結點的右子樹*/
                          free(s);           /*注意不是free(p),因為p的關鍵字被s的關鍵字覆蓋,s已無用*/
    }
    return T;
}

完整程式碼如下:

#include <iostream>
#include<stdio.h>
#include<malloc.h>
using namespace std;
typedef int Elemtype;
/*二叉排序樹的二叉連結串列儲存結構*/
typedef struct BTNode{
    Elemtype key;                       /*記錄的關鍵字,忽略記錄的其他資料項*/
    struct BTNode *lchild,*rchild;
}BTNode,*BSTree;

/*二叉排序樹的查詢*/
BTNode *SearchBST(BSTree T,int key)      /*T指向二叉排序樹的根結點*/
{
    if(T==NULL)                     /*空樹,查詢失敗*/
        return NULL;
    if(key==T->key)             /*查詢成功*/
        return T;
    if(key<T->key)
        return SearchBST(T->lchild,key);        /*查詢左子樹*/
    if(key>T->key)
        return SearchBST(T->rchild,key);       /*查詢右子樹*/
}

/*在二叉排序樹上插入一個結點*/
BSTree InsertBST(BSTree T,BTNode *s)
{  /*在以T為根的二叉樹上插入一個指標s所指向的結點並返回根指標T*/
    if(T==NULL)         /*如果T是空樹,則新插入的結點S作為新的樹根*/
        T=s;
    else
    {
        if(s->key<T->key)
            T->lchild=InsertBST(T->lchild,s);       /*遞迴插到T的左子樹中*/
        if(s->key>T->key)
            T->lchild=InsertBST(T->lchild,s);        /*遞迴插到T的右子樹中*/
    }
    return T;
}

/*二叉排序樹的插入*/
BSTree InsertBST_key(BSTree T,int key)
{/*在以T為根結點的二叉排序樹上查詢關鍵字為key的記錄,若不存在將其插入*/
    BTNode *s=SearchBST(T,key);
    if(s!=NULL)
    {
        printf("\n關鍵字%d已存在!\n",s->key);
        return T;
    }
    s=(BTNode *)malloc(sizeof(BTNode));         /*生成一個結點空間*/
    if(s==NULL)
        printf("Error\n");
    s->key=key;
    s->lchild=s->rchild=NULL;
    T=InsertBST(T,s);               /*在二叉排序樹上插入該結點*/
    return T;
}

/*二叉排序樹的建立*/
BSTree CreateBST()      /*由空樹開始,輸入關鍵字序列,建立一棵二叉排序樹*/
{
    BSTree T=NULL,s=NULL;
    int key;
    printf("輸入關鍵字序列,輸入-1結束\n");
    while(1)
    {
        scanf("%d",&key);
        if(key==-1)
            break;
        s=(BTNode *)malloc(sizeof(BTNode));         /*生成一個結點空間*/
        s->key=key;
        s->lchild=s->rchild=NULL;
        T=InsertBST(T,s);                   /*在二叉排序樹中插入該結點*/
    }
    return T;
}

/*為了刪除操作而修改的二叉排序樹查詢*/
BTNode *SearchBST_F(BSTree T,int key,BSTree *F)
{   /*T指向根結點,*F儲存指向key的雙親的指標*/
    /*查詢成功,返回指向key的記錄指標,查詢失敗返回NULL*/
    if(T==NULL)
        return NULL;
    if(key==T->key)
        return T;
    *F=T;
    if(key<T->key)
        return SearchBST_F(T->lchild,key,F);
    if(key>T->key)
        return SearchBST_F(T->rchild,key,F);
}

/*二叉排序樹的刪除*/
BSTree DeleteBST(BSTree T,BTNode *p,BTNode *f)
{/*刪除p指標指向的結點,f指向*p的雙親結點*/
 /*T是指向根結點的指標*/
    BTNode *par,*s;
    int kind;
    if(p->lchild==NULL&&p->rchild==NULL)            /*情況1,*p為葉子結點*/
        kind=1;
    else if(p->rchild==NULL)                /*情況2,*p只有左子樹*/
        kind=2;
    else if(p->lchild==NULL)                /*情況3,*p只有右子樹*/
        kind=3;
    else                                                    /*情況4,*p左右子樹非空*/
        kind=4;
    switch(kind)
    {
        case 1:    if(f==NULL)         /*p指向根結點,樹中只有根結點*/
                                T=NULL;             /*刪除結點*p,T變空樹*/
                        else
                        {
                                if(f->lchild==p)       /* *p是*f的左孩子*/
                                    f->lchild=NULL;
                                else                           /* *p是*f的右孩子*/
                                    f->rchild==NULL;
                        }
                        free(p);                    /*刪除結點釋放空間*/
                        break;
        case 2:    if(f==NULL)          /*f為NULL,*p為根結點,且只有左子樹*/
                                T=p->lchild;
                        else
                        {
                            if(f->lchild==p)       /* *p是*f的左子樹*/
                                f->lchild=p->lchild;
                            else                         /* *p是*f的右子樹*/
                                f->rchild=p->lchild;
                        }
                        free(p);                       /*刪除結點釋放空間*/
                        break;
        case 3:     if(f==NULL)        /*f為NULL,*p為根結點,且只有左子樹*/
                                T=p->rchild;
                           else
                           {
                               if(p==f->lchild)
                                    f->lchild=p->rchild;
                               else
                                    f->rchild=p->rchild;
                           }
                           free(p);
                           break;
        case 4:     par=p;
                          s=p->lchild;
                          while(s->rchild!=NULL)        /*找到p左子樹的關鍵字最大(最右下)的結點*/
                          {
                              par=s;
                              s=s->rchild;
                          }
                          p->key=s->key;        /*s結點的值覆蓋p結點的值*/
                          if(par==p)           /*處理特殊情況,*p的左孩子為*s*/
                                par->lchild=s->lchild;
                          else
                                par->rchild=s->lchild;      /*s的左子樹連線到s的雙親結點作為雙親結點的右子樹*/
                          free(s);           /*注意不是free(p),因為p的關鍵字被s的關鍵字覆蓋,s已無用*/
    }
    return T;
}

BSTree SearchDeleteBST(BSTree T,int key)
{
        BTNode *f=NULL,*p=NULL;
        p=SearchBST_F(T,key,&f);        /*查詢key,p指向key,f指向雙親*/
        if(p!=NULL)
            T=DeleteBST(T,p,f);
        else
            printf("關鍵字為key的記錄不存在!\n");
        return T;
}


int main()
{

    return 0;
}