二叉搜索樹


一、二叉搜索樹的特點

二叉搜索樹的特點:對於樹中的每個節點X,它的左子樹中所有關鍵字值小於X的關鍵字值,而它的右子樹中所有關鍵字值大於X的關鍵字值。

根據這個性質,對一個二叉樹進行中序遍歷,如果是單調遞增的,則可以說明這個樹是二叉搜索樹

LeetCode題目98:驗證二叉搜索樹(https://leetcode-cn.com/problems/validate-binary-search-tree/)就可以對這個二叉樹進行中序遍歷,然后判斷是否單調遞增的,如果是單調遞增的,說明是二叉搜索樹。否則不是二叉搜索樹。

 

二、二叉搜索樹的查找

過程:首先和根節點進行比較,如果等於根節點,則返回。如果小於根節點,則在根節點的左子樹進行查找。如果大於根節點,則在根節點的右子樹進行查找。

 1 /* 查找以t為根節點的樹中,是否包含x */
 2 Position Find(ElementType x, SearchTree t)
 3 {
 4     if (t == NULL) {
 5         return NULL;
 6     } else if (x < t->element) {
 7         return Find(x, t->left);
 8     } else if (x > t->element) {
 9         return Find(x, t->right);
10     } else {
11         return t;
12     }
13 }
View Code

 

三、查找最大值和最小值

查找最小值:從根開始,如果有左兒子,則向左進行。直到左兒子為空,則當前節點為最小值。

 1 Position FindMin(SearchTree t)
 2 {
 3     if (t == NULL) {
 4         return NULL;
 5     } else if (t->left == NULL) {
 6         return t;
 7     } else {
 8         return FindMin(t->left);
 9     }
10 }
View Code

查找最大值:從根開始,如果有右兒子,則向右進行。直到右兒子為空,則當前節點為最大值。

 1 Position FindMax(SearchTree t)
 2 {
 3     if (t == NULL) {
 4         return NULL;
 5     }
 6 
 7     while (t->right != NULL)
 8     {
 9         t = t->right;
10     }
11     return t;  
12 }
View Code

這里查找最小值運用了遞歸,而查找最大值運用了非遞歸實現。

 

四、二叉搜索樹的插入

二叉搜索樹的插入過程和查找類似。新插入的節點一般在遍歷的路徑上的最后一點上,即葉子節點。如果待插入的數據比當前節點的數據大,並且當前節點的右兒子為空,則將待插入的節點插到右兒子位置上。如果右兒子不為空,則再遞歸的遍歷右兒子。如果小於當前節點,則對左兒子做類似的處理就行。

 1 SearchTree Insert(ElementType x, SearchTree t)
 2 {
 3     if (t == NULL) {
 4         /* 插入第一個節點 */
 5         t = (SearchTree)malloc(sizeof(struct TreeNode));
 6         if (t == NULL) {
 7             return NULL;
 8         }
 9         t->element = x;
10         t->left = NULL;
11         t->right = NULL;
12     } else if (x < t->element) {
13         t->left = Insert(x, t->left);
14     } else if (x > t->element) {
15         t->right = Insert(x, t->right);
16     }
17     return t;
18 }
View Code

 

五、二叉搜索樹的刪除

二叉搜索樹的刪除分為以下幾個情況:

1、待刪除的節點是一個葉子節點,即它沒有左右兒子。此時只要將它的父節點指向NULL即可。

2、如果節點有一個兒子,則該節點可以在其父節點調整指針繞過該節點后刪除。

3、如果有兩個兒子,一般的刪除策略是用其右子樹中最小的數據代替該節點的數據並遞歸地刪除那個節點。因為右子樹中最小地節點不可能有左兒子(如果有,則說明不是最小的),所以第二次刪除更容易。(其實也就是將有兩個兒子的情況轉為容易處理的情況1或者2)。

 1 /* 刪除策略
 2  * 1、如果待刪除節點只有一個兒子,則將該節點的父節點的兒子節點指針指向該節點的兒子節點,
 3  * 然后刪除該節點.
 4  * 2、如果待刪除節點有兩個兒子,用右子樹中最小的數據代替該節點的數據並遞歸地刪除那個節點。
 5  * 因為右子樹中最小地節點不可能有左兒子,所以第二次刪除更容易.
 6  */
 7  SearchTree Delete(ElementType x, SearchTree t)
 8  {
 9      Position tmp;
10      if (t == NULL) {  
11          return NULL;
12      }
13      if (x < t->element) {
14          t->left = Delete(x, t->left);
15      } else if (x > t->element) {
16          t->right = Delete(x, t->right);
17      } else if (t->left && t->right) {
18          tmp = FindMin(t->right);
19          t->element = tmp->element;
20          t->right = Delete(t->element, t->right);
21      } else {
22          tmp = t;
23          if (t->left) {
24              t = t->left;
25          } else if (t->right) {
26              t = t->right;
27          }
28          free(tmp);
29          tmp = NULL;
30      }
31      return t;
32  }
View Code

 

六、建立一棵空樹

 1 SearchTree MakeEmpty(SearchTree t)
 2 {
 3     if (t != NULL) {
 4         MakeEmpty(t->left);
 5         MakeEmpty(t->right);
 6         free(t);
 7         t = NULL;
 8     }
 9     return NULL;
10 }
View Code

 

附錄:

完整代碼:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 #define ElementType int
  5 struct TreeNode;
  6 typedef struct TreeNode *Position;
  7 typedef struct TreeNode *SearchTree;
  8 
  9 SearchTree MakeEmpty(SearchTree t);
 10 Position Find(ElementType x, SearchTree t);
 11 Position FindMin(SearchTree t);
 12 Position FindMax(SearchTree t);
 13 SearchTree Insert(ElementType x, SearchTree t);
 14 SearchTree Delete(ElementType x, SearchTree t);
 15 
 16 struct TreeNode
 17 {
 18     ElementType element;
 19     SearchTree left;
 20     SearchTree right;
 21 };
 22 
 23 SearchTree MakeEmpty(SearchTree t)
 24 {
 25     if (t != NULL) {
 26         MakeEmpty(t->left);
 27         MakeEmpty(t->right);
 28         free(t);
 29         t = NULL;
 30     }
 31     return NULL;
 32 }
 33 
 34 /* 查找以t為根節點的樹中,是否包含x */
 35 Position Find(ElementType x, SearchTree t)
 36 {
 37     if (t == NULL) {
 38         return NULL;
 39     } else if (x < t->element) {
 40         return Find(x, t->left);
 41     } else if (x > t->element) {
 42         return Find(x, t->right);
 43     } else {
 44         return t;
 45     }
 46 }
 47 
 48 Position FindMin(SearchTree t)
 49 {
 50     if (t == NULL) {
 51         return NULL;
 52     } else if (t->left == NULL) {
 53         return t;
 54     } else {
 55         return FindMin(t->left);
 56     }
 57 }
 58 
 59 Position FindMax(SearchTree t)
 60 {
 61     if (t == NULL) {
 62         return NULL;
 63     }
 64 
 65     while (t->right != NULL)
 66     {
 67         t = t->right;
 68     }
 69     return t;  
 70 }
 71 
 72 SearchTree Insert(ElementType x, SearchTree t)
 73 {
 74     if (t == NULL) {
 75         /* 插入第一個節點 */
 76         t = (SearchTree)malloc(sizeof(struct TreeNode));
 77         if (t == NULL) {
 78             return NULL;
 79         }
 80         t->element = x;
 81         t->left = NULL;
 82         t->right = NULL;
 83     } else if (x < t->element) {
 84         t->left = Insert(x, t->left);
 85     } else if (x > t->element) {
 86         t->right = Insert(x, t->right);
 87     }
 88     return t;
 89 }
 90 
 91 /* 刪除策略
 92  * 1、如果待刪除節點只有一個兒子,則將該節點的父節點的兒子節點指針指向該節點的兒子節點,
 93  * 然后刪除該節點.
 94  * 2、如果待刪除節點有兩個兒子,用右子樹中最小的數據代替該節點的數據並遞歸地刪除那個節點。
 95  * 因為右子樹中最小地節點不可能有左兒子,所以第二次刪除更容易.
 96  */
 97  SearchTree Delete(ElementType x, SearchTree t)
 98  {
 99      Position tmp;
100      if (t == NULL) {  
101          return NULL;
102      }
103      if (x < t->element) {
104          t->left = Delete(x, t->left);
105      } else if (x > t->element) {
106          t->right = Delete(x, t->right);
107      } else if (t->left && t->right) {
108          tmp = FindMin(t->right);
109          t->element = tmp->element;
110          t->right = Delete(t->element, t->right);
111      } else {
112          tmp = t;
113          if (t->left) {
114              t = t->left;
115          } else if (t->right) {
116              t = t->right;
117          }
118          free(tmp);
119          tmp = NULL;
120      }
121      return t;
122  }
123 
124  void PrintfTree(SearchTree t)
125  {
126      if (t == NULL) {
127          return;
128      }
129      printf("%d ", t->element);
130      PrintfTree(t->left);
131      PrintfTree(t->right);
132      return;
133  }
134 
135  int main()
136  {
137      ElementType i;
138      SearchTree binary_tree = NULL;
139 
140      /******** Insert *********/
141      for (i = 1; i < 11; i++) {
142          binary_tree = Insert(i, binary_tree);
143      }
144      PrintfTree(binary_tree);
145      printf("\n");
146 
147     /******** Find *********/
148      Position pos = NULL;
149      pos = Find(6, binary_tree);
150      if (pos != NULL) {
151          printf("find %d\n", pos->element);
152      } else {
153          printf("Not find 6\n");
154      }
155      pos = Find(11, binary_tree);
156      if (pos != NULL) {
157          printf("find %d\n", pos->element);
158      } else {
159          printf("Not find 11\n");
160      }
161 
162     /******** FindMin *********/
163      Position min = NULL;
164      min = FindMin(binary_tree);
165      if (min) {
166          printf("find min, min: %d\n", min->element);
167      } else {
168          printf("not find min\n");
169      }
170 
171     /******** FindMax *********/
172      Position max = NULL;
173      max = FindMax(binary_tree);
174      if (max) {
175          printf("find max, max: %d\n", max->element);
176      } else {
177          printf("not find max\n");
178      }
179 
180 
181     Position del = NULL;
182     del = Delete(8, binary_tree);
183     PrintfTree(binary_tree);
184     printf("\n");
185 
186     binary_tree = MakeEmpty(binary_tree);
187     PrintfTree(binary_tree);
188     return 0;
189  }
View Code

 


免責聲明!

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



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