二叉排序樹的基本算法

        寫了二叉排序樹,基本的插入,查找,刪除運算,下面是我的詳細代碼:

 

#include <stdio.h>
#include <stdlib.h>

typedef  struct BiTNode{//定義二叉排序樹的結構 
         int data;//值 
         struct BiTNode *lchild,*rchild;//左右孩子 
         }BiTNode,*BiTree;

void inorder(BiTree T);  //中序遍歷 
int DeleteBST(BiTree T,int key);   //刪除特定元素   
int SearchBST(BiTree u,int key);//查找元素 
BiTree InsertBST(BiTree T,int key);//插入元素

int main()//測試函數 
{
    int i,data,n,m;
    BiTree tree = NULL;//定義BiTNode 型的指針 
    
    printf("Input your data:");
    for(i = 0; i < 7; i++)//輸入值 
    {
          scanf("%d",&data);
          tree = InsertBST(tree,data);//構造樹 
    }
    
    printf("中序遍歷結果:"); 
    inorder(tree);
    printf("\n"); 
    
    printf("輸入要查找的元素:");
    scanf("%d",&n); 
    printf("查找結果:");
    printf("%d\n",SearchBST(tree,n));
    
    printf("輸入要刪除的元素:");
    scanf("%d",&m);
    DeleteBST(tree,m);
    inorder(tree);
     
    system("pause");
    return 0;
}

int SearchBST(BiTree u,int key)//二叉排序樹、查找的遞歸算法 
{
    BiTree p = u;
    
    if(!p)
          return 0;
    else if(key == p->data)
          return 1;
    else if(key > p->data)
          return SearchBST(p->rchild,key);
    else
          return SearchBST(p->lchild,key);
}

BiTree InsertBST(BiTree T,int key)//二叉排序樹的插入 
{
       BiTree f = T,p = T;
       
       while(p)
       {
               if(p->data == key)//如果待插元素等於根結點的值 ,則不用插入 
                     return T;//返回根結點 
               f = p;//用f記下查找路徑上的最後一個訪問的結點 
               p = (key < p->data)? p->lchild:p->rchild;//如果根結點值與待插元素不等,重置p,根據大小關係 
       }
       
       p = (BiTNode *)malloc(sizeof(BiTNode));//申請待插元素所需空間 
       p->data = key;//待插元素賦給此結點 
       p->lchild = p->rchild = NULL;//將插入的元素所在結點的左右孩子均置爲空 
               
       //插入操作: 
       if(T == NULL)//T爲空,吧P賦給T 
            T = p;
       else if(key < f->data)//否則,插入待插元素 
            f->lchild = p;//根據大小關係 
       else 
            f->rchild = p;//根據大小關係插入 
       
       return T;//返回樹根 
}    

void inorder(BiTree T)//根據二叉排序樹的特點,中序遍歷後爲順序輸出,元素已經排好序 
{
     if(T)
     {
          inorder(T->lchild); 
          printf("%d ",T->data);
          inorder(T->rchild);
     }
}

int DeleteBST(BiTree T,int key)//刪除算法,刪除其中一個關鍵字爲key的結點 
{
    BiTree p = T,f,q,s,root = T;
    
    while(p)
    {
            if(p->data == key)//找出關鍵字爲key的結點 
                break;
            
            f = p;//記錄關鍵字key結點的父結點 
            p = (key < p->data)? p->lchild:p->rchild;//在P的左右子樹中尋找 
    }
    
    if(!p)
          return 0;//二叉排序樹中無關鍵字爲key的結點 
    
    if(p->lchild == NULL && p->rchild == NULL)//P沒有左右子樹 
    {
         if(p == T)
              T = NULL;//刪除的是根結點 
         else if(p == f->lchild)//f爲關鍵字爲key的結點p的父結點 
              f->lchild = NULL;//將f的左孩子置爲空 
         else
              f->rchild = NULL;//將f的右孩子置爲空 
         free(p);//刪除結點p 
    }
    else if(p->lchild == NULL && p->rchild != NULL)
    {//P無左子樹,有右子樹 
         if(f->lchild == p)
              f->lchild = p->rchild;//將p的右子樹鏈接到其父結點的左鏈上
         else
              f->rchild = p->rchild;//將p的右子樹鏈接到其父結點的右鏈上
         free(p);
    }
    else if(p->lchild != NULL && p->rchild == NULL)
    {//p有左子樹無右子樹
         if(f->lchild == p)
              f->lchild = p->lchild;//將p的左子樹鏈接到其父結點的左鏈上
         else
              f->rchild = p->lchild;//將p的左子樹鏈接到其父結點的右鏈上
         free(p);
    }
    else if(p->lchild != NULL && p->rchild != NULL)//p既有左子樹又有右子樹
    {
         q = p;
         s = p->lchild;//轉左
         
         while(s->rchild)
         {//然後向右到盡頭
              q = s;
              s = s->rchild;//s指向被刪節點的"前驅"(中序前驅)
         }
         
         p->data = s->data;//以p的中序前趨結點s代替p(即把s的數據複製到p中)
         
         if(q != p)
              q->rchild = s->lchild;//重接q的右子樹
         else
              q->lchild = s->lchild;//重接q的左子樹。
         free(s);
    }
}    
        


       其他操作我覺得都容易,在刪除結點時,情況有點複雜,下面是一點小解析:
              
    
      假設在二叉排序樹上被刪除結點時*p(指向節點的指針爲p),其雙親結點爲*f(結點指針爲f),且不是一般性,可設*p是*f的左孩子。

     分三種情況進行:

      1. 若p結點爲葉子節點,即p沒有左右孩子,由於刪除葉子節點不破壞整棵樹的結構,則只需修改雙親節點的指針即可。

      2. 若p結點只有左孩子或者只有右孩子,此時只要將其左孩子或右孩子直接成爲其雙親結點f的左子樹即可。

      3. 若p結點左右子樹均不空,先找到*p的中序前趨結點*s(注意*s*p的左子樹中的最右下的結點,它的右鏈域爲空),然後有兩種做法:

其一是令p的左子樹爲f的左子樹,而p的右子樹爲s的右子樹;其二是令p的直接前驅(或直接後繼)代替p,然後再從二叉排序樹中刪去它的直接前驅(或直接後繼)。
       


     
   
                          
       
    
   

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章