程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 算法導論-二叉排序樹

算法導論-二叉排序樹

編輯:C++入門知識

一、定義與性質


定義
  二叉排序樹(Binary Sort Tree)又稱二叉查找(搜索)樹(Binary Search Tree)。其定義為:二叉排序樹或者是空樹,或者是滿足如下性質的二叉樹:
①若它的左子樹非空,則左子樹上所有結點的值均小於根結點的值;
②若它的右子樹非空,則右子樹上所有結點的值均大於根結點的值;
③左、右子樹本身又各是一棵二叉排序樹。
  上述性質簡稱二叉排序樹性質(BST性質),故二叉排序樹實際上是滿足BST性質的二叉樹。

 

性質
  (1) 二叉排序樹中任一結點x,其左(右)子樹中任一結點y(若存在)的關鍵字必小(大)於x的關鍵字。
  (2) 二叉排序樹中,各結點關鍵字是惟一的。
  注意:
  實際應用中,不能保證被查找的數據集中各元素的關鍵字互不相同,所以可將二叉排序樹定義中BST性質(1)裡的"小於"改為"大於等於",或將BST性質(2)裡的"大於"改為"小於等於",甚至可同時修改這兩個性質。
  (3) 按中序遍歷該樹所得到的中序序列是一個遞增有序序列。

 


二、插入與刪除
       插入與刪除操作是二叉排序樹中最常用也是最重要的兩個操作。

       插入過程是:
  (a)若二叉排序樹T為空,則為待插入的關鍵字key申請一個新結點,並令其為根;
  (b)若二叉排序樹T不為空,則將key和根的關鍵字比較:
           (i)若二者相等,則說明樹中已有此關鍵字key,無須插入。
           (ii)若key<T→key,則將key插入根的左子樹中。
           (iii)若key>T→key,則將它插入根的右子樹中。
  子樹中的插入過程與上述的樹中插入過程相同。如此進行下去,直到將key作為一個新的葉結點的關鍵字插入到二叉排序樹中,或者直到發現樹中已有此關鍵字為止。


     刪除過程:

    

(1) 進行查找
       查找時,令p指向當前訪問到的結點,parent指向其雙親(其初值為NULL)。若樹中找不到被刪結點則返回,否則被刪結點是*p。
(2) 刪去*p。
       刪*p時,應將*p的子樹(若有)仍連接在樹上且保持BST性質不變。按*p的孩子數目分三種情況進行處理。

         刪除*p結點的三種情況
         a.*p是葉子(即它的孩子數為0)
       無須連接*p的子樹,只需將*p的雙親*parent中指向*p的指針域置空即可。

  

         b.*p只有一個孩子*child
       只需將*child和*p的雙親直接連接後,即可刪去*p。
            注意:*p既可能是*parent的左孩子也可能是其右孩子,而*child可能是*p的左孩子或右孩子,故共有4種狀態。

 


            c.*p有兩個孩子
       先令q=p,將被刪結點的地址保存在q中;然後找*q的中序後繼*p,並在查找過程中仍用parent記住*p的雙親位置。*q的中序後繼*p一定是*q的右子樹中最左下的結點,它無左子樹。因此,可以將刪去*q的操作轉換為刪去的*p的操作,即在釋放結點*p之前將其數據復制到*q中,就相當於刪去了*q。

 


三、代碼清單


[cpp]
#include<stdio.h>  
#include<stdlib.h>  
#define maxSize 20    
#define maxWidth 20    
typedef int KeyType; //假定關鍵字類型為整數  
typedef struct node { //結點類型  
    KeyType key; //關鍵字項  
    struct node *lchild,*rchild;//左右孩子指針  
} BSTNode,BSTree; 
//typedef BSTNode *BSTree; //BSTree是二叉排序樹的類型  
//先序遍歷    
void preOrder(BSTree *BT)   
{   
    if(BT!= NULL)   
    {   
        printf("%d",BT->key);   
        preOrder(BT->lchild);   
        preOrder(BT->rchild);   
 
    }   
}   
//中序遍歷    
void inOrder(BSTree *BT)   
{   
    if(BT!= NULL)   
    {   
        inOrder(BT->lchild);   
        printf("%d",BT->key);   
        inOrder(BT->rchild);   
    }   
}   
//後序遍歷    
void postOrder(BSTree *BT)   
{   
    if(BT!= NULL)   
    {   
        postOrder(BT->lchild);   
        postOrder(BT->rchild);   
        printf("%d",BT->key);   
    }   
}  
 
//層次法打印樹    
void dispTree(BSTree *BT)   
{   
    BSTree *stack[maxSize],*p;   
    int level[maxSize][2],top,n,i,width=4;   
    if(BT!=NULL)   
    {   
        printf("Display a tree by hollow means.\n");   
        top=1;   
        stack[top]=BT;//push root point to stack.    
        level[top][0]=width;   
        while(top>0)   
        {   
            p=stack[top];   
            n=level[top][0];   
            for(i=1;i<=n;i++)   
                printf(" ");   
            printf("%d",p->key);   
            for(i=n+1;i<maxWidth;i+=2)   
                printf("--");   
            printf("\n");   
            top--;   
            if(p->rchild!=NULL)   
            {   
                top++;   
                stack[top]=p->rchild;   
                level[top][0]=n+width;   
                level[top][1]=2;   
            }   
            if(p->lchild!=NULL)   
            {   
                top++;   
                stack[top]=p->lchild;   
                level[top][0]=n+width;   
                level[top][1]=1;   
            }   
        }   
    }   
}   
 
/* 向二叉排序樹中加入一個結點 
要改變指針,需要傳遞指針的指針*/ 
int InsertNode(BSTree **tree, KeyType key) 

    BSTNode *p= NULL, *parent = NULL; 
    BSTNode *pNewNode = (BSTNode *)malloc(sizeof(BSTNode)); 
    if (pNewNode==NULL) 
    { 
        return -1; 
    } 
    /* 新建結點賦值,特別是左右子結點指針要賦值為NULL */ 
    pNewNode->key = key; 
    pNewNode->lchild = NULL; 
    pNewNode->rchild = NULL; 
    /* 二叉排序樹是空樹 */ 
    if (*tree==NULL) 
    { 
        *tree = pNewNode; 
        return 0; 
 
    } 
    else 
    { 
 
        p = *tree; 
        /* 尋找插入位置 */ 
        while (NULL != p) 
        { 
            /* key值已在二叉排序樹中 */ 
            if (p->key == key) 
            { 
                return 0; 
            } 
            else 
            { 
                parent = p; 
                p = (p->key < key) ? p->rchild : p->lchild; 
            } 
        } 
        if (parent->key < key) 
        { 
            parent->rchild = pNewNode; 
        } 
        else 
        { 
            parent->lchild = pNewNode; 
        } 
        return 0; 
    } 

//刪除節點  
 /* 通過值查找並刪除一個結點 */ 
 int delNode(BSTree **tree, KeyType key) 
 { 
     BSTNode *p = NULL, *q = NULL, *parent = NULL, *child = NULL; 
     p = *tree; 
     /* parent為NULL表示根結點的父親為NULL */ 
     while (NULL != p) 
     { 
         if (p->key == key) 
         { 
             break; 
         } 
         else 
         { parent = p; 
         p = (p->key < key) ? p->rchild : p->lchild; 
         } 
     } 
     /* p為NULL時, 表示沒有找到結點值為key的結點 */ 
     if (NULL == p) 
     { 
         return 0; 
     } 
     /* p, q現在都是保存了待刪結點指針 */ 
     q = p; 
      
     /* 待刪結點有兩個兒子結點,進行一下轉化 */ 
     if (NULL != p->lchild && NULL != p->rchild) 
     { 
    //找中序後繼,先右拐,然後左走到底  
         parent = p; 
         p = p->rchild; 
         while (NULL != p->lchild) 
         { 
             parent = p; 
             p = p->lchild; 
         } 
         /* p中保存了待刪結點右子樹中最左下的結點指針, parent中就保存了該結點父親指針 */ 
         child = p->rchild; 
     } 
      
     /* parent保存待刪結點的父親結點指針, child保存了待刪結點的兒子結點
     
//實際刪除的是待刪節點的直接後繼,下面是刪除直接後繼的過程,(待刪結點至多只有一個兒子, 有兩個會轉化為0個或1個右結點)
     
      待刪結點是根結點 */ 
     if (NULL == parent) 
     { 
         *tree = child; 
     } 
     else 
     { 
         /*待刪結點是父親結點的左兒子*/ 
         if (parent->lchild == p) 
         { 
             parent->lchild = child; 
         } 
         else 
         { 
             parent->rchild = child; 
         } 
    //將實際刪除的節點的key值賦給原先要刪除的節點  
         if (p != q) 
         { 
             q->key = p->key; 
         } 
     } 
     free(p); 
     return 0; 
 } 
//二叉排序樹查找  
BSTNode* SearchBST(BSTree *T,KeyType key) 
{ //在二叉排序樹T上查找關鍵字為key的結點,成功時返回該結點位置,否則返回NUll  
    if(T==NULL) //遞歸的終結條件  
        return NULL; //T為空,查找失敗;  
    if(key==T->key) 
        //成功,返回找到的結點位置  
    { 
        printf("Got it!"); 
        return T; 
    } 
 
    if(key<T->key) 
        return SearchBST(T->lchild,key); 
    else 
        return SearchBST(T->rchild,key);//繼續在右子樹中查找  
} //SearchBST  
int main() 

    int n;   
    BSTree *B=NULL; 
    printf("Input number to initialize a BSTree:"); 
    while(1) 
    { 
        scanf("%d",&n); 
        if(n==0) break; 
        InsertNode(&B, n); 
    }    
    dispTree(B);  
    printf("PreOrder:"); 
    preOrder(B); 
    printf("\n"); 
    printf("Search a node:"); 
    scanf("%d",&n); 
    SearchBST(B,n); 
    printf("\n"); 
    printf("Delete a node:"); 
    scanf("%d",&n); 
    delNode(&B,n); 
    dispTree(B);  
    printf("PreOrder:"); 
    preOrder(B); 
    printf("\n"); 
    return 1; 

#include<stdio.h>
#include<stdlib.h>
#define maxSize 20 
#define maxWidth 20 
typedef int KeyType; //假定關鍵字類型為整數
typedef struct node { //結點類型
 KeyType key; //關鍵字項
 struct node *lchild,*rchild;//左右孩子指針
} BSTNode,BSTree;
//typedef BSTNode *BSTree; //BSTree是二叉排序樹的類型
//先序遍歷 
void preOrder(BSTree *BT) 

 if(BT!= NULL) 
 { 
  printf("%d",BT->key); 
  preOrder(BT->lchild); 
  preOrder(BT->rchild); 

 } 

//中序遍歷 
void inOrder(BSTree *BT) 

 if(BT!= NULL) 
 { 
  inOrder(BT->lchild); 
  printf("%d",BT->key); 
  inOrder(BT->rchild); 
 } 

//後序遍歷 
void postOrder(BSTree *BT) 

 if(BT!= NULL) 
 { 
  postOrder(BT->lchild); 
  postOrder(BT->rchild); 
  printf("%d",BT->key); 
 } 
}

//層次法打印樹 
void dispTree(BSTree *BT) 

 BSTree *stack[maxSize],*p; 
 int level[maxSize][2],top,n,i,width=4; 
 if(BT!=NULL) 
 { 
  printf("Display a tree by hollow means.\n"); 
  top=1; 
  stack[top]=BT;//push root point to stack. 
  level[top][0]=width; 
  while(top>0) 
  { 
   p=stack[top]; 
   n=level[top][0]; 
   for(i=1;i<=n;i++) 
    printf(" "); 
   printf("%d",p->key); 
   for(i=n+1;i<maxWidth;i+=2) 
    printf("--"); 
   printf("\n"); 
   top--; 
   if(p->rchild!=NULL) 
   { 
    top++; 
    stack[top]=p->rchild; 
    level[top][0]=n+width; 
    level[top][1]=2; 
   } 
   if(p->lchild!=NULL) 
   { 
    top++; 
    stack[top]=p->lchild; 
    level[top][0]=n+width; 
    level[top][1]=1; 
   } 
  } 
 } 

/* 向二叉排序樹中加入一個結點
要改變指針,需要傳遞指針的指針*/
int InsertNode(BSTree **tree, KeyType key)
{
 BSTNode *p= NULL, *parent = NULL;
 BSTNode *pNewNode = (BSTNode *)malloc(sizeof(BSTNode));
 if (pNewNode==NULL)
 {
  return -1;
 }
 /* 新建結點賦值,特別是左右子結點指針要賦值為NULL */
 pNewNode->key = key;
 pNewNode->lchild = NULL;
 pNewNode->rchild = NULL;
 /* 二叉排序樹是空樹 */
 if (*tree==NULL)
 {
  *tree = pNewNode;
  return 0;

 }
 else
 {

  p = *tree;
  /* 尋找插入位置 */
  while (NULL != p)
  {
   /* key值已在二叉排序樹中 */
   if (p->key == key)
   {
    return 0;
   }
   else
   {
    parent = p;
    p = (p->key < key) ? p->rchild : p->lchild;
   }
  }
  if (parent->key < key)
  {
   parent->rchild = pNewNode;
  }
  else
  {
   parent->lchild = pNewNode;
  }
  return 0;
 }
}
//刪除節點
 /* 通過值查找並刪除一個結點 */
 int delNode(BSTree **tree, KeyType key)
 {
     BSTNode *p = NULL, *q = NULL, *parent = NULL, *child = NULL;
     p = *tree;
     /* parent為NULL表示根結點的父親為NULL */
     while (NULL != p)
     {
         if (p->key == key)
         {
             break;
         }
         else
         { parent = p;
         p = (p->key < key) ? p->rchild : p->lchild;
         }
     }
     /* p為NULL時, 表示沒有找到結點值為key的結點 */
     if (NULL == p)
     {
         return 0;
     }
     /* p, q現在都是保存了待刪結點指針 */
     q = p;
    
     /* 待刪結點有兩個兒子結點,進行一下轉化 */
     if (NULL != p->lchild && NULL != p->rchild)
     {
 //找中序後繼,先右拐,然後左走到底
         parent = p;
         p = p->rchild;
         while (NULL != p->lchild)
         {
             parent = p;
             p = p->lchild;
         }
         /* p中保存了待刪結點右子樹中最左下的結點指針, parent中就保存了該結點父親指針 */
         child = p->rchild;
     }
    
     /* parent保存待刪結點的父親結點指針, child保存了待刪結點的兒子結點
    
//實際刪除的是待刪節點的直接後繼,下面是刪除直接後繼的過程,(待刪結點至多只有一個兒子, 有兩個會轉化為0個或1個右結點)
    
      待刪結點是根結點 */
     if (NULL == parent)
     {
         *tree = child;
     }
     else
     {
         /*待刪結點是父親結點的左兒子*/
         if (parent->lchild == p)
         {
             parent->lchild = child;
         }
         else
         {
             parent->rchild = child;
         }
 //將實際刪除的節點的key值賦給原先要刪除的節點
         if (p != q)
         {
             q->key = p->key;
         }
     }
     free(p);
     return 0;
 }
//二叉排序樹查找
BSTNode* SearchBST(BSTree *T,KeyType key)
{ //在二叉排序樹T上查找關鍵字為key的結點,成功時返回該結點位置,否則返回NUll
 if(T==NULL) //遞歸的終結條件
  return NULL; //T為空,查找失敗;
 if(key==T->key)
  //成功,返回找到的結點位置
 {
  printf("Got it!");
  return T;
 }

 if(key<T->key)
  return SearchBST(T->lchild,key);
 else
  return SearchBST(T->rchild,key);//繼續在右子樹中查找
} //SearchBST
int main()
{
 int n; 
 BSTree *B=NULL;
 printf("Input number to initialize a BSTree:");
 while(1)
 {
  scanf("%d",&n);
  if(n==0) break;
  InsertNode(&B, n);
 } 
 dispTree(B);
 printf("PreOrder:");
 preOrder(B);
 printf("\n");
 printf("Search a node:");
 scanf("%d",&n);
 SearchBST(B,n);
 printf("\n");
 printf("Delete a node:");
 scanf("%d",&n);
 delNode(&B,n);
 dispTree(B);
 printf("PreOrder:");
 preOrder(B);
 printf("\n");
 return 1;
}

運行結果:

 \


 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved