之前的博客中提到过,我学习采用的参考书是《数据结构与算法分析——C语言描述》。这门书的组织安排与国内广泛实用的教材《数据结构——C语言版》比较不同。这本书描述了一些树和二叉树的概念,举例讲解了什么是树的三种遍历之后,就开始重点讲解二叉查找树、平衡二叉树、AVL树、伸展树、B数了。这一篇博客,重点学习二叉查找树的概念和基本操作。

    大家都知道,树的定义本身就带有递归性。因此,树的很多操作都涉及到了递归。二叉查找树的定义如下:

    1.二叉查找树首先是一棵二叉树;

    2.二叉查找树除了是二叉树外,还具有以下性质:对于树中的任何一个节点X,其左子树中的所有节点的关键字均小于X的关键字的值;而其右子树中的所有关键字的值均大于X的关键字的值。下面两棵二叉树中,左边的二叉树是二叉查找树而右边的不是。

 

    二叉查找树的数据结构定义如下:

  1. typedef int ElementType; 
  2. typedef struct TreeNode *Position; 
  3. typedef Position BiSearchTree; 
  4. struct TreeNode 
  5. { 
  6.     ElementType Element; 
  7.     BiSearchTree Left,Right; 
  8. }; 

    二叉查找树的常用操作如下:

  1. BiSearchTree MakeEmpty(BiSearchTree Tree); 
  2. Position Find(ElementType X, BiSearchTree T); 
  3. Position FindMin(BiSearchTree T); 
  4. Position FindMax(BiSearchTree T); 
  5. BiSearchTree Insert(ElementType X,BiSearchTree T); 
  6. BiSearchTree Delete(ElementType X, BiSearchTree T); 

    二叉排序树的操作与之前学习的一些数据结构的操作相比,可能难理解一些。下面我们挑比较难的几个一一讲解。

    1.二叉查找树中查找指定的元素Find

    二叉排序树的性质是二叉排序树很多操作的基本依据。既然要查找指定元素X,先比较X与根节点元素的关系,如果刚好相等,直接返回啦;如果X小于根节点的元素值,那么去根节点的左子树中查找,也就是调用Find方法,只是传递的参数是X和根节点的左子树;如果X大于根节点的元素值,那么去根节点的右子树中查找,也就是调用Find函数,只是传递的参数是X和根节点的右子树。

    2.查找最小元素FindMin和最大元素FindMax

    这两个操作是类似的。采用迭代或者递归都可以实现,查找最小元素只需要沿着左子树访问下去,查找最大元素则相反。下面我们会分别采用递归和迭代实现这两个操作。

    3.插入操作Insert

    插入操作其实类似于查找操作,插入过过程其实就是先得找到一个合适的位置。插入其实有下面几个情况:

    (1)如果函数传进来的是空树,那么创建一棵树,将其元素值设置为X。这种情况显而易见;

    (2)如果不是空树,那就比较根节点元素值和X的大小,如果X的值小于根节点的元素值,而此时的根节点的左子树为空,那么根节点的左孩子就是X元素的归宿啦;同样的道理,如果X的值大于根节点的元素值,而此时根节点的右子树为空,那么根节点的右孩子就是X元素的归宿啦。把握住这一点其实基本上就能把握住这个操作了。文字描述可能比较抽象,下面看图:

    左边的图,如果要插入5,沿着树一直找到节点4,这时5>4并且4的右孩子为空,那么5就是4的右孩子。右边的图,要想插入8,沿着树找到9,发现8<9且9的左孩子为空,那么8就是9的左孩子。

    当然,在实现这样一个过程的时候可以使用递归。

    4.删除操作Delete

    删除操作是我认为最复杂最不好理解的一个操作。如果没有仔细想明白整个过程,上来就看代码的话可能会很晕。删除操作分两步:第一步是查找,找的过程就涉及元素值之间的比较。我们重点说找到之后的操作。假设我们找到了这个节点,现在要删除,涉及三种情况:

    (1)该节点是叶子。这还有什么好说的,直接删了一了百了;

    (2)该节点只有一个孩子节点。也不复杂,让该节点的父节点直接指向其子节点就行了。当然,也别忘了回收该节点;

    (3)该节点有两个孩子:找到该节点右子树中最小的节点,将其元素值赋给该节点,然后删除那个最小节点。这种情况看图:

 

    说了半天了,下面看看完整的代码:

  1. #include <stdio.h> 
  2. #include <stdlib.h> 
  3.  
  4. typedef int ElementType; 
  5. typedef struct TreeNode *Position; 
  6. typedef Position BiSearchTree; 
  7. struct TreeNode 
  8. { 
  9.     ElementType Element; 
  10.     BiSearchTree Left,Right; 
  11. }; 
  12.  
  13. //建立一颗空树 
  14. BiSearchTree MakeEmpty(BiSearchTree Tree) 
  15. { 
  16.     if(!Tree) 
  17.     { 
  18.         MakeEmpty(Tree->Left); 
  19.         MakeEmpty(Tree->Right); 
  20.         free(Tree); 
  21.     } 
  22.     return NULL; 
  23. } 
  24. //二叉查找树的Find操作 
  25. Position Find(ElementType X, BiSearchTree T) 
  26. { 
  27.     if(T == NULL) 
  28.     { 
  29.         return NULL; 
  30.     } 
  31.     else 
  32.     { 
  33.         //关键字小于根节点的元素值 
  34.         if(X < T->Element) 
  35.         { 
  36.             return Find(X,T->Left); 
  37.         } 
  38.         else if(X > T->Element) 
  39.         { 
  40.             return Find(X,T->Right); 
  41.         } 
  42.         else 
  43.         { 
  44.             return T; 
  45.         } 
  46.     } 
  47. } 
  48. //查找最小值:递归写法 
  49. Position FindMin(BiSearchTree T) 
  50. { 
  51.     if(T == NULL) 
  52.     { 
  53.         return NULL; 
  54.     } 
  55.     else 
  56.     { 
  57.         if(T->Left == NULL)  
  58.         { 
  59.             return T; 
  60.         }else 
  61.         { 
  62.             return FindMin(T->Left); 
  63.         } 
  64.     } 
  65. } 
  66.  
  67. //查找最大值:非递归写法 
  68. Position FindMax(BiSearchTree T) 
  69. { 
  70.     if(T->Right != NULL) 
  71.     { 
  72.         while(T->Right != NULL) 
  73.         { 
  74.             T = T->Right; 
  75.         } 
  76.     } 
  77.     return T; 
  78. } 
  79. //插入元素X 
  80. BiSearchTree Insert(ElementType X,BiSearchTree T) 
  81. { 
  82.     //当树为空树时 
  83.     if(T == NULL) 
  84.     { 
  85.         T = malloc(sizeof(struct TreeNode)); 
  86.         if(T == NULL) 
  87.         { 
  88.             fprintf(stderr,"Out of Space!!!"); 
  89.         } 
  90.         else 
  91.         { 
  92.             T->Element = X; 
  93.             T->Left = NULL; 
  94.             T->Right = NULL; 
  95.         } 
  96.     } 
  97.     //树不为空时 
  98.     else 
  99.     { 
  100.         if(X < T->Element)  
  101.         { 
  102.             T->Left = Insert(X,T->Left); 
  103.         } 
  104.         else if(X > T->Element)  
  105.         { 
  106.             T->Right = Insert(X,T->Right); 
  107.         } 
  108.         else 
  109.         { 
  110.             //do nothing! 
  111.         } 
  112.     } 
  113.     return T; 
  114. } 
  115.  
  116. //删除节点X 
  117. BiSearchTree Delete(ElementType X, BiSearchTree T) 
  118. { 
  119.     Position TmpCell; 
  120.     if(T==NULL) 
  121.     { 
  122.         fprintf(stderr,"Element does not exist!"); 
  123.     } 
  124.     else if(X < T->Element) 
  125.     { 
  126.         T->Left = Delete(X,T->Left); 
  127.     } 
  128.     else if(X > T->Element) 
  129.     { 
  130.         T->Right = Delete(X,T->Right); 
  131.     } 
  132.     else if(T->Left && T->Right) 
  133.     { 
  134.         TmpCell = FindMin(T->Right); 
  135.         T->Element = TmpCell->Element; 
  136.         T->Right = Delete(T->Element,T->Right); 
  137.     } 
  138.     else 
  139.     { 
  140.         TmpCell = T; 
  141.         if(T->Left == NULL) 
  142.         { 
  143.             T = T->Right; 
  144.         } 
  145.         else if(T->Right == NULL) 
  146.         { 
  147.             T = T->Left; 
  148.         } 
  149.         free(TmpCell); 
  150.     } 
  151.     return T; 
  152. } 
  153.  
  154. int main(void) 
  155. { 
  156.     BiSearchTree T; 
  157.     int index; 
  158.     int arr[10] = {10,9,8,7,6,1,2,3,4,5}; 
  159.     T = NULL; 
  160.     for(index=0; index < 10; index++) 
  161.     { 
  162.         T = Insert(arr[index],T); 
  163.     } 
  164.     T = Insert(18,T); 
  165.     T = Insert(15,T); 
  166.     printf("The minimum element is %d\n",FindMin(T)->Element); 
  167.     printf("The maxmium element is %d\n",FindMax(T)->Element); 
  168.     return 0; 
  169. }