二叉排序樹(查詢、插入、刪除)


“二叉排序樹,又稱為二叉查找樹。它或者是一顆空樹,或者具有下列性質的二叉樹。

  • 若它的左子樹不空,則左子樹上所有節點的值均小於它的根節點的值;

  • 若它的右子樹不空,則右子樹上所有節點的值均大於它的根節點的值;

  • 它的左、右子樹也分別為二叉排序樹。

構造一顆二叉排序樹的目的,其實並不是為了排序,而是為了提高查找和插入刪除關鍵字的速度。不管怎么說,在一個有序數據集上的查找,速度總是要快於無序數據集的,而二叉排序樹這種非線性的結構,也有利於插入和刪除的實現。” 

通俗的講,二叉排序樹的本質就是一顆二叉樹,只是關鍵字的排序比較有規律,能夠利用二叉樹的遞歸特性進行很方便的操作。在對於二叉排序樹的基本操作中,包括:根據數據集構建二叉排序樹(沒有要查找的關鍵字,就插入)、查找、刪除。其中,刪除操作時最麻煩的,插入和查找的思路很像,下面詳解。

 

1、二叉排序樹的查找操作

 

首先定義一個二叉樹的結構。

[cpp]  view plain  copy
 
  1. /* 二叉排序樹的節點結構定義 */  
  2. typedef struct BiTNode  
  3. {  
  4.     int data;  
  5.     struct BiTNode *lchild, *rchild;  
  6. } BiTNode, *BiTree;  

查找操作思路:

    先查找其根節點,如果根節點的數據與key值相等,則返回該根節點,並且返回TRUE;

    否則, 如果key值大於根節點,則查詢其右子樹;

                如果小於根節點,則查詢其左子樹。

代碼如下:

 

[cpp]  view plain  copy
 
  1. int SearchBST( BiTree T, int key, BiTree f, BiTree *p )  
  2. {  
  3.     /* 遞歸查找二叉排序樹T中是否存在key */  
  4.     /* 指針f指向T的雙親,其初始調用值為NULL */  
  5.     /* 若查找成功,則指針p指向該數據元素節點,並返回TRUE */  
  6.     /* 否則指針p指向查找路徑上訪問的最后一個節點並返回FALSE */  
  7.     if( !T )  
  8.     {     
  9.         *p = f;     //這是f唯一被用到的位置。  
  10.         return FALSE;     
  11.     }  
  12.     else  
  13.     {  
  14.         if( key == T->data )  
  15.         {   *p = T;     return TRUE; }  
  16.         else if( key > T->data )  
  17.             return SearchBST( T->rchild, key, T, p );        /* 在右子樹繼續查找 */  
  18.         else      
  19.             return SearchBST( T->lchild, key, T, p );        /* 在左子樹繼續查找 */  
  20.         }  
  21. }  
  22.   
  23. int SearchBST2( BiTree T, int key, BiTree f, BiTree *p )  
  24. {  
  25.     /*非遞歸*/  
  26.     BiTree s;  
  27.     if( !T )  
  28.     {   *p = f;     return FALSE;   }  
  29.     else  
  30.     {  
  31.         while( T )  
  32.         {  
  33.             if( key == T->data )  
  34.             {   *p = T;     return TRUE;    }  
  35.             if( key > T->data )  
  36.             {   s = T;  T = T->rchild;       }  
  37.             else  
  38.             {   s = T;  T = T->lchild;       }  
  39.         }  
  40.         *p = s;  
  41.         return FALSE;  
  42.     }  
  43. }  


 

2、二叉排序樹的插入操作

代碼如下:

 

[cpp]  view plain  copy
 
  1. int InsertBST1( BiTree *T, int key )  
  2. {  
  3.     /* 當二叉排序樹T中不存在關鍵字等於key的數據元素時 */  
  4.     /* 插入key並返回TRUE,否則返回FALSE */  
  5.     /* 調用查找函數SearchBST,非遞歸 */  
  6.     BiTree p, s;  
  7.     if( !SearchBST2( *T, key, NULL, &p ) )  
  8.     {  
  9.         s = (BiTree)malloc(sizeof(BiTNode));  
  10.         s->data = key;  
  11.         s->lchild = s->rchild = NULL;  
  12.         if( !p )  
  13.             *T = s;             /* 插入s為根節點,此前樹為空樹 */  
  14.         else if( key > p->data )  
  15.             p->rchild = s;       /* 插入s為右孩子 */  
  16.         else  
  17.             p->lchild = s;       /* 插入s為左孩子 */  
  18.         return TRUE;  
  19.     }  
  20.     return FALSE;  
  21. }  
  22.   
  23. int InsertBST2( BiTree *T, int key )  
  24. {  
  25.     /* 當二叉排序樹T中不存在關鍵字等於key的數據元素時 */  
  26.     /* 插入key並返回TRUE,否則返回FALSE */  
  27.     /* 未調用查找函數,遞歸插入 */  
  28.     if( !(*T) )                                 /* 樹為空, */  
  29.     {  
  30.         (*T) = (BiTree)malloc(sizeof(BiTNode)); /* 這個位置要留心,要重新分配空間,*T為空,說明未曾分配空間 */  
  31.         (*T)->data = key;  
  32.         (*T)->lchild = (*T)->rchild = NULL;  
  33.         return TRUE;  
  34.     }  
  35.     if( key == (*T)->data )  
  36.         return FALSE;  
  37.     if( key > (*T)->data )          
  38.         return InsertBST2( &((*T)->rchild), key );       /* 插入右孩子 */  
  39.     else  
  40.         return InsertBST2( &((*T)->lchild), key );       /* 插入左孩子 */  
  41. }  

 

3、二叉樹的刪除操作(相對復雜一些)

 

    刪除節點有三種情況分析:

        a. 葉子節點;(直接刪除即可)




 

 b. 僅有左或右子樹的節點;(上移子樹即可)

 c. 左右子樹都有的節點。( 用刪除節點的直接前驅或者直接后繼來替換當前節點,調整直接前驅或者直接后繼的位置)

代碼如下:

 

[cpp]  view plain  copy
 
  1. int DeleteBST(BiTree *T, int key)  
  2. {  
  3.     /* 若二叉排序樹T中存在關鍵字等於key的數據元素時,則刪除該數據元素節點 */  
  4.     /* 並返回TRUE;否則返回FALSE */  
  5.     if( !(*T))  
  6.         return FALSE;   /* 不存在關鍵字等於key的數據元素 */  
  7.     else  
  8.     {  
  9.         if( key == (*T)->data )  
  10.             Delete(T);  
  11.         else if( key < (*T)->data)  
  12.             return DeleteBST(&(*T)->lchild, key);  
  13.         else  
  14.             return DeleteBST(&(*T)->rchild, key);  
  15.     }  
  16. }  
  17.   
  18. int Delete(BiTree *p)  
  19. {  
  20.     /* 從二叉排序樹中刪除節點p, 並重接它的左或右子樹 */  
  21.     BiTree q, s;  
  22.     if(  !(*p)->lchild && !(*p)->rchild ) /* p為葉子節點 */  
  23.         *p = NULL;  
  24.     else if( !(*p)->lchild ) /* 左子樹為空,重接右子樹 */  
  25.     {  
  26.         q = *p;   
  27.         *p = (*p)->rchild;  
  28.         free(q);  
  29.     }  
  30.     else if( !(*p)->rchild ) /* 右子樹為空,重接左子樹 */  
  31.     {  
  32.         q = *p;  
  33.         *p = (*p)->lchild;         
  34.         free(q);  
  35.     }  
  36.     else                        /* 左右子樹均不為空 */  
  37.     {  
  38.         q = *p;  
  39.         s = (*p)->lchild;  
  40.         while(s->rchild)     /* 轉左,然后向右走到盡頭*/  
  41.         {  
  42.             q = s;  
  43.             s = s->rchild;  
  44.         }  
  45.         (*p)->data = s->data;  
  46.         if( q != *p )               /* 判斷是否執行上述while循環 */  
  47.             q->rchild = s->lchild;    /* 執行上述while循環,重接右子樹 */   
  48.         else  
  49.             q->lchild = s->lchild;    /* 未執行上述while循環,重接左子樹 */  
  50.         free(s);  
  51.     }  
  52.     return TRUE;  
  53. }  

 

 

總結:二叉樹以鏈式方式存儲,保持了鏈接存儲結構在執行插入或刪除操作時不用移動元素的優點,只要找到合適的插入和刪除位置后,僅需要修改鏈接指針節課。插入刪除的時間性能比較好。而丟與二拆排序樹的查找,走的就是從根節點到要查找的節點的路徑,其比較次數等於給定值的節點在二叉排序樹的層數。極端情況,最少為1次,即根節點就是要找的節點,最多也不會超過樹的深度。也就是說,二叉排序樹的查找性能取決於二叉排序樹的形狀。可問題就在於,二叉排序樹的形狀是不確定的。

例如{62,88,58,47,35,73,51,99,37,93}這樣的數組,我們可以構建一顆正常的二叉排序樹。但是如果數組元素的次序是從小到大有序,如{35,37,47,51,58,62,73,88,93,99},則二拆排序樹就成了極端的單支樹,注意它依然是一顆二叉排序樹。同樣是查找節點99,左圖只需要兩次比較,而右圖就需要10次比較才可以得到結果,而這差異很大。


也就是說,我們希望二叉排序樹是比較平衡的,即其深度與完全二叉樹相同。

這樣就延續到了另一篇博客中要講解的平衡二叉樹。

 

附加:完整代碼

 

[cpp]  view plain  copy
 
  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. #define TRUE 1  
  4. #define FALSE 0  
  5.   
  6. /* 二叉排序樹的節點結構定義 */  
  7. typedef struct BiTNode  
  8. {  
  9.     int data;  
  10.     struct BiTNode *lchild, *rchild;  
  11. } BiTNode, *BiTree;  
  12.   
  13.   
  14. int SearchBST( BiTree T, int key, BiTree f, BiTree *p )  
  15. {  
  16.     /* 遞歸查找二叉排序樹T中是否存在key */  
  17.     /* 指針f指向T的雙親,其初始調用值為NULL */  
  18.     /* 若查找成功,則指針p指向該數據元素節點,並返回TRUE */  
  19.     /* 否則指針p指向查找路徑上訪問的最后一個節點並返回FALSE */  
  20.     if( !T )  
  21.     {     
  22.         *p = f;     //這是f唯一被用到的位置。  
  23.         return FALSE;     
  24.     }  
  25.     else  
  26.     {  
  27.         if( key == T->data )  
  28.         {   *p = T;     return TRUE; }  
  29.         else if( key > T->data )  
  30.             return SearchBST( T->rchild, key, T, p );        /* 在右子樹繼續查找 */  
  31.         else      
  32.             return SearchBST( T->lchild, key, T, p );        /* 在左子樹繼續查找 */  
  33.         }  
  34. }  
  35.   
  36. int SearchBST2( BiTree T, int key, BiTree f, BiTree *p )  
  37. {  
  38.     /*非遞歸*/  
  39.     BiTree s;  
  40.     if( !T )  
  41.     {   *p = f;     return FALSE;   }  
  42.     else  
  43.     {  
  44.         while( T )  
  45.         {  
  46.             if( key == T->data )  
  47.             {   *p = T;     return TRUE;    }  
  48.             if( key > T->data )  
  49.             {   s = T;  T = T->rchild;       }  
  50.             else  
  51.             {   s = T;  T = T->lchild;       }  
  52.         }  
  53.         *p = s;  
  54.         return FALSE;  
  55.     }  
  56. }  
  57.   
  58.   
  59. int InsertBST1( BiTree *T, int key )  
  60. {  
  61.     /* 當二叉排序樹T中不存在關鍵字等於key的數據元素時 */  
  62.     /* 插入key並返回TRUE,否則返回FALSE */  
  63.     /* 調用查找函數SearchBST,非遞歸 */  
  64.     BiTree p, s;  
  65.     if( !SearchBST2( *T, key, NULL, &p ) )  
  66.     {  
  67.         s = (BiTree)malloc(sizeof(BiTNode));  
  68.         s->data = key;  
  69.         s->lchild = s->rchild = NULL;  
  70.         if( !p )  
  71.             *T = s;             /* 插入s為根節點,此前樹為空樹 */  
  72.         else if( key > p->data )  
  73.             p->rchild = s;       /* 插入s為右孩子 */  
  74.         else  
  75.             p->lchild = s;       /* 插入s為左孩子 */  
  76.         return TRUE;  
  77.     }  
  78.     return FALSE;  
  79. }  
  80.   
  81. int InsertBST2( BiTree *T, int key )  
  82. {  
  83.     /* 當二叉排序樹T中不存在關鍵字等於key的數據元素時 */  
  84.     /* 插入key並返回TRUE,否則返回FALSE */  
  85.     /* 未調用查找函數,遞歸插入 */  
  86.     if( !(*T) )                                 /* 樹為空, */  
  87.     {  
  88.         (*T) = (BiTree)malloc(sizeof(BiTNode)); /* 這個位置要留心,要重新分配空間,*T為空,說明未曾分配空間 */  
  89.         (*T)->data = key;  
  90.         (*T)->lchild = (*T)->rchild = NULL;  
  91.         return TRUE;  
  92.     }  
  93.     if( key == (*T)->data )  
  94.         return FALSE;  
  95.     if( key > (*T)->data )          
  96.         return InsertBST2( &((*T)->rchild), key );       /* 插入右孩子 */  
  97.     else  
  98.         return InsertBST2( &((*T)->lchild), key );       /* 插入左孩子 */  
  99. }  
  100.   
  101.   
  102. void order(BiTree t)//中序輸出    
  103. {    
  104.     if(t == NULL)    
  105.         return ;    
  106.     order(t->lchild);    
  107.     printf("%d ", t->data);    
  108.     order(t->rchild);    
  109. }   
  110.   
  111.   
  112.   
  113. int DeleteBST(BiTree *T, int key)  
  114. {  
  115.     /* 若二叉排序樹T中存在關鍵字等於key的數據元素時,則刪除該數據元素節點 */  
  116.     /* 並返回TRUE;否則返回FALSE */  
  117.     if( !(*T))  
  118.         return FALSE;   /* 不存在關鍵字等於key的數據元素 */  
  119.     else  
  120.     {  
  121.         if( key == (*T)->data )  
  122.             Delete(T);  
  123.         else if( key < (*T)->data)  
  124.             return DeleteBST(&(*T)->lchild, key);  
  125.         else  
  126.             return DeleteBST(&(*T)->rchild, key);  
  127.     }  
  128. }  
  129.   
  130. int Delete(BiTree *p)  
  131. {  
  132.     /* 從二叉排序樹中刪除節點p, 並重接它的左或右子樹 */  
  133.     BiTree q, s;  
  134.     if(  !(*p)->lchild && !(*p)->rchild ) /* p為葉子節點 */  
  135.         *p = NULL;  
  136.     else if( !(*p)->lchild ) /* 左子樹為空,重接右子樹 */  
  137.     {  
  138.         q = *p;   
  139.         *p = (*p)->rchild;  
  140.         free(q);  
  141.     }  
  142.     else if( !(*p)->rchild ) /* 右子樹為空,重接左子樹 */  
  143.     {  
  144.         q = *p;  
  145.         *p = (*p)->lchild;       /* 不太理解 */  
  146.         free(q);  
  147.     }  
  148.     else                        /* 左右子樹均不為空 */  
  149.     {  
  150.         q = *p;  
  151.         s = (*p)->lchild;  
  152.         while(s->rchild)     /* 轉左,然后向右走到盡頭*/  
  153.         {  
  154.             q = s;  
  155.             s = s->rchild;  
  156.         }  
  157.         (*p)->data = s->data;  
  158.         if( q != *p )               /* 判斷是否執行上述while循環 */  
  159.             q->rchild = s->lchild;    /* 執行上述while循環,重接右子樹 */   
  160.         else  
  161.             q->lchild = s->lchild;    /* 未執行上述while循環,重接左子樹 */  
  162.         free(s);  
  163.     }  
  164.     return TRUE;  
  165. }  
  166. void main()  
  167. {  
  168.     int i;  
  169.     int a[10] = {62,88,58,47,35,73,51,99,37,93};  
  170.     BiTree T = NULL;  
  171.     for( i = 0; i < 10; i++ )  
  172.         InsertBST1(&T, a[i]);  
  173.     printf("中序遍歷二叉排序樹:\n");  
  174.     order(T);  
  175.     printf("\n");  
  176.     printf("刪除58后,中序遍歷二叉排序樹:\n");  
  177.     DeleteBST(&T,58);  
  178.     order(T);  
  179.     printf("\n");  
  180. }  


 


 原文:http://blog.csdn.net/wangyunyun00/article/details/23708055


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM