《算法導論》第十四章----數據結構的擴張(動態順序統計)

《算法導論》學習記錄目錄html

這一章是對第十三章紅黑樹的擴張(PS:關於紅黑樹的介紹見連接)。在現實應用中咱們常常須要在一些數據結構(鏈表、二叉樹)上添加一些特性來解決問題。之前看書的時候從沒有認真看過這一章,總是以爲沒什麼用。此次認真的看完、思考後,以爲真心不錯。以前總是對擴張數據結構沒什麼概念,在解決某些問題的時候沒有考慮使用某些算法或者數據結構的擴張去解決問題。第一是本身對算法和數據結構的認識還不夠深刻;第二是沒有結合問題的特性和某些算法或者數據結構的特性來解決問題。之後要多加註意。算法

 順序統計樹數據結構

順序統計樹是在紅黑樹的上添加一個size特性,每一個結點都含有size域,size域的值爲以該點爲根的子樹的結點數(包括根結點),即子樹的大小。以下圖所示。ide

圖中忽略了NIL結點(哨兵),該結點的size域爲0。函數

size域值的計算公式:size[x] = size[left[x]] + size[right[x]] + 1學習

首先來看在添加size域後,插入和刪除結點的過程當中如何維持它的特性。測試

插入操做spa

紅黑樹的插入是有兩個步驟:1、從根結點開始,沿着樹降低,找到合適的位置並將新結點插入;2、重新結點開始沿着樹上升,須要的時候修改結點的顏色和進行旋轉操做以保持紅黑樹的性質。設計

那麼從根結點到新結點插入的父結點的路上的結點都受到新結點的影響,它們的size的值應該要增長1(新結點的size值爲1)。而後再進行旋轉,旋轉會影響size域的值,那麼在旋轉操做上添加調整size域的操做。(如圖所示)指針

 

左旋轉操做修改後代碼以下:

 1 /*
 2  * x結點上進行左旋轉,y結點(x結點的右兒子)的左兒子成爲x結點的新右兒子
 3  * x結點成爲y結點的左兒子的新父結點
 4  * x結點的父結點成爲y結點的新父結點,y結點成爲x結點的新父結點
 5  * x結點成爲y結點的新左兒子
 6  */
 7 void Left_Rotate(RB_Tree *T, RB_TreeNode *x){
 8     RB_TreeNode *y = x->right;       //x點右兒子          
 9     x->right = y->left;              //y結點的左兒子會成爲x結點的右兒子
10     if(y->left != NIL)
11         y->left->parent = x;         //若是y有左兒子,y的左兒子的父結點爲x
12     y->parent = x->parent;
13     if(x->parent == NIL)
14         T->root = y;                //若是x的父結點爲哨兵,說明x爲根結點,則y成爲根結點
15     else if(x == x->parent->left)
16         x->parent->left = y;        
17     else
18         x->parent->right = y;       //判斷x爲其父結點的左、右兒子,y成爲x父結點對應的兒子
19     y->left = x;                    //y的左兒子爲x
20     x->parent = y;                  //x的父結點爲y
21 
22     /*調整size域*/
23     y->size = x->size;
24     x->size = x->left->size + x->right->size + 1;
25 }

 

插入操做修改後代碼以下:

 1 /*
 2  * 插入函數,注意插入結點與其在樹中對應的父結點的連接(須要記錄父結點)。
 3  * 從根結點出發,不停用當前結點與插入的值比較,若是當前結點的值比較大就往當前結點的左兒子走,相反就往右兒子走,直到當前結點爲空,
 4  * 在過程當中記錄當前結點的父結點。
 5  * 運行時間爲O(h),h爲樹的高度。由於整個過程是一條沿着根結點降低的路徑。
 6  */
 7 void RB_Insert(RB_Tree *T, int key){
 8     RB_TreeNode *z;
 9     z = (RB_TreeNode *)malloc(sizeof(RB_TreeNode));         //新建結點
10     z->value = key;
11     z->color = RED;
12     z->parent = z->left = z->right = NIL;
13     z->size = 1;
14     RB_TreeNode *x = T->root;
15     RB_TreeNode *y = NIL;
16     while(x != NIL){
17         y = x;
18         x->size += 1;
19         if(x->value < key)
20             x = x->right;
21         else
22             x = x->left;
23     }
24     z->parent = y;
25     if(y == NIL){
26         T->root = z;
27         T->root->parent = NIL;
28         T->root->parent->color = BLACK;
29         T->root->size = 1;
30     }
31     else if(z->value < y->value)
32         y->left = z;
33     else
34         y->right = z;
35     RB_Insert_Fixup(T, z);                                 //插入調整,維持紅黑性質
36 }

增長新結點從根結點到葉子的遍歷的路上總共有O(lgn)個結點,因此維護size域的額外代價爲O(lgn)。

 

刪除操做

紅黑樹的刪除也是兩個步驟:1、查找真正要刪除的結點;2、進行調整以維護紅黑樹的性質。

對於要刪除的結點,它的父結點到根結點的路徑上的全部結點的size域都會受到影響。因此要遍歷刪除結點到根結點的路徑,並減小每一個結點的size值。若是須要的時候進行旋轉操做,維護紅黑樹的性質和調整size域。

刪除操做修改後代碼以下:

 1 /*
 2  * 刪除結點函數,首先要肯定真正刪除的結點是那個。
 3  * 若是z沒有子結點,直接將z的父結點對應的指針指向NULL
 4  * 若是z只有一個子節點,直接將z的父結點對應的指針指向z的子結點
 5  * 若是z有兩個子結點,實際上要刪除的不是z,而是z的後繼,,再用z的後繼的內容代替z的內容
 6  */
 7 
 8 void RB_Delete(RB_Tree *T, RB_TreeNode *z){
 9     RB_TreeNode *x = NULL;
10     RB_TreeNode *y = NULL;
11     RB_TreeNode *p = NULL;
12 
13     if(z->left == NIL || z->right == NIL)
14         y = z;
15     else
16         y = RB_Tree_Successor(z);
17     if(y->left != NIL)
18         x = y->left;
19     else
20         x = y->right;
21     x->parent = y->parent;
22     if(y->parent == NIL)
23         T->root = x;
24     else if(y == y->parent->left)
25         y->parent->left = x;
26     else
27         y->parent->right = x;
28    
29     /* 從刪除結點遍歷一條路徑到根結點,並減小size值*/ 
30     p = y;
31     while(p != T->root){
32         p->parent->size = p->parent->size - 1;
33         p = p->parent;
34     }
35 
36     if(y != z)
37         z->value = y->value;
38     if(y->color == BLACK)
39         RB_Delete_Fixup(T, x);          //當實際要刪除的結點y爲黑色時才須要進行調整
40 }

從刪除結點遍歷到根結點,該路徑的有O(lgn)個結點,因此維護size域的額外代價爲O(lgn)。

 

接着咱們來看經過添加size域能夠幫助咱們在O(lgn)時間內肯定:1、任意的順序統計量;2、一個元素在集合的位置是多少。

檢索具備給定排序的元素

對於x結點,size[left[x]]爲以x爲根結點的子樹進行中序遍歷時排在x以前的結點的個數,那麼size[left[x]] + 1就是以x爲根的子樹中x的排序。

查找在某個集合裏第i個小的關鍵字的結點的指針。

首先從根結點開始查詢,若是當前子樹的根結點的size[left[x]] + 1的值等於排序i,那麼當前的子樹的根結點wei第i小元素。若是i小於size[left[x]] + 1,那麼第i小元素在當前子樹的左子樹中;若是i大於size[left[x]] + 1,那麼第i小元素在在當前子樹的右子樹中,而且爲右子樹中爲第(i-size[left[x]] + 1)小元素。(這個與第九章的選擇方法差很少:第九章戳這裏)。

代碼以下:

 1 RB_TreeNode * os_select(RB_TreeNode *x, int i){
 2     int r = x->left->size + 1;
 3     if(i == r)
 4         return x;
 5     else if(i < r){
 6         return os_select(x->left, i);
 7     }
 8     else{
 9         return os_select(x->right, i-r);
10     }
11 }

最壞狀況爲從根結點遍歷到葉結點,由於紅黑樹的高度爲O(lgn),因此通過的結點數爲O(lgn),因此運行時間爲O(lgn)。

 

肯定一個元素的秩

給定一個結點x的指針,返回其在樹中中序遍歷後的到的線性位置。

x的秩爲中序遍歷後排在x以前的結點個數加上一。

代碼以下:

 1 int os_rank(RB_Tree *T, RB_TreeNode *x){
 2     int r = x->left->size + 1;
 3     RB_TreeNode *y = x;
 4     while(y != T->root){
 5         if(y == y->parent->right){
 6             r += (y->parent->left->size + 1);
 7         }
 8         y = y->parent;
 9     }
10     return r;
11 }

最壞狀況也是從根結點遍歷到葉結點,因此運行時間爲O(lgn)。

 

所有代碼以下:

  1 /*
  2  * =====================================================================================
  3  *
  4  *       Filename:  order_statistic_tree.c
  5  *
  6  *    Description:  
  7  *
  8  *        Version:  1.0
  9  *        Created:  12/01/2013 05:21:02 PM
 10  *       Revision:  none
 11  *       Compiler:  gcc
 12  *
 13  *         Author:  alan (), alan19920626@gmail.com
 14  *   Organization:  
 15  *
 16  * =====================================================================================
 17  */
 18 
 19 
 20 #include <stdio.h>
 21 #include <stdlib.h>
 22 
 23 #define RED 1
 24 #define BLACK 0
 25 
 26 typedef struct RB_TreeNode {
 27     int value;
 28     int color;
 29     int size;
 30     struct RB_TreeNode * parent;
 31     struct RB_TreeNode * left;
 32     struct RB_TreeNode * right;
 33 }RB_TreeNode;                       //紅黑樹結點結構體
 34 
 35 typedef struct RB_Tree {
 36     RB_TreeNode * root;
 37 }RB_Tree;                           //紅黑樹結構體,根結點
 38 
 39 RB_TreeNode  NILL = { -1, BLACK, 0, NULL, NULL, NULL };
 40 RB_TreeNode *NIL = &NILL;                               //NIL結點指針
 41 
 42 void Left_Rotate(RB_Tree *T, RB_TreeNode *x);
 43 
 44 void Right_Rotate(RB_Tree *T, RB_TreeNode *x);
 45 
 46 void RB_Insert(RB_Tree *T, int key);
 47 
 48 void RB_Insert_Fixup(RB_Tree *T, RB_TreeNode *z);
 49 
 50 void RB_Delete(RB_Tree *T, RB_TreeNode *z);
 51 
 52 void RB_Delete_Fixup(RB_Tree *T, RB_TreeNode *x);
 53 
 54 RB_TreeNode * RB_Search(RB_TreeNode *x, int key);
 55 
 56 RB_TreeNode * RB_Tree_Minimum(RB_TreeNode *x);
 57 
 58 RB_TreeNode * RB_Tree_Maximum(RB_TreeNode *x);
 59 
 60 RB_TreeNode * RB_Tree_Successor(RB_TreeNode *x);
 61 
 62 RB_TreeNode * RB_Tree_Predecesor(RB_TreeNode *x);
 63 
 64 void Inorder_RB_Tree_Walk(RB_TreeNode *x);
 65 
 66 void free_men(RB_TreeNode *x);
 67 
 68 RB_TreeNode * os_select(RB_TreeNode *x, int i);
 69 
 70 int os_rank(RB_Tree *T, RB_TreeNode *x);
 71 
 72 int main(){
 73     RB_Tree *T;
 74     T->root = NIL;
 75    
 76     int n, value, i;
 77     scanf("%d", &n);
 78     for(i = 1; i<= n; i++){
 79         scanf("%d", &value);
 80         RB_Insert(T, value);
 81         Inorder_RB_Tree_Walk(T->root);    
 82         printf("\n");
 83     }
 84     RB_TreeNode *s = RB_Search(T->root, 3);
 85     if(s != NIL)
 86         printf("%d is exists!\n", s->value);
 87     /*Inorder_RB_Tree_Walk(T->root);
 88 
 89     printf("\n");*/
 90 
 91     printf("%d\n", os_select(T->root, 3)->value);
 92 
 93     printf("%d\n", os_rank(T, s));
 94 
 95     //printf("%d\n", RB_Tree_Minimum(T->root)->value);
 96     //printf("%d\n", RB_Tree_Maximum(T->root)->value);
 97     //printf("%d\n", RB_Tree_Successor(s)->value);
 98     //printf("%d\n", RB_Tree_Predecesor(s)->value);
 99     RB_Delete(T, s);
100     Inorder_RB_Tree_Walk(T->root);
101     printf("\n");
102 
103     return 0;
104 }
105 
106 /*
107  * x結點上進行左旋轉,y結點(x結點的右兒子)的左兒子成爲x結點的新右兒子
108  * x結點成爲y結點的左兒子的新父結點
109  * x結點的父結點成爲y結點的新父結點,y結點成爲x結點的新父結點
110  * x結點成爲y結點的新左兒子
111  */
112 void Left_Rotate(RB_Tree *T, RB_TreeNode *x){
113     RB_TreeNode *y = x->right;       //x點右兒子          
114     x->right = y->left;              //y結點的左兒子會成爲x結點的右兒子
115     if(y->left != NIL)
116         y->left->parent = x;         //若是y有左兒子,y的左兒子的父結點爲x
117     y->parent = x->parent;
118     if(x->parent == NIL)
119         T->root = y;                //若是x的父結點爲哨兵,說明x爲根結點,則y成爲根結點
120     else if(x == x->parent->left)
121         x->parent->left = y;        
122     else
123         x->parent->right = y;       //判斷x爲其父結點的左、右兒子,y成爲x父結點對應的兒子
124     y->left = x;                    //y的左兒子爲x
125     x->parent = y;                  //x的父結點爲y
126 
127     /*調整size域*/
128     y->size = x->size;
129     x->size = x->left->size + x->right->size + 1;
130 }
131 
132 /*
133  * x結點上進行右旋轉,y結點(x結點的左兒子)的右兒子成爲x結點的新左兒子
134  * x結點成爲y結點的右兒子的新父結點
135  * x結點的父結點成爲y結點的新父結點,y結點成爲x結點的新父結點
136  * x結點成爲y結點的新右兒子
137  * PS:代碼的解釋可參照左旋轉
138  */
139 void Right_Rotate(RB_Tree *T, RB_TreeNode *x){
140     RB_TreeNode *y = x->left;
141     x->left = y->right;
142     if(y->right != NIL)
143         y->right->parent = x;
144     y->parent = x->parent;
145     if(x->parent == NIL)
146         T->root = y;
147     else if(x == x->parent->left)
148         x->parent->left = y;
149     else
150         x->parent->right = y;
151     y->right = x;
152     x->parent = y;
153 
154     /* */
155     y->size = x->size;
156     x->size = x->left->size + x->right->size + 1;
157 }
158 
159 /*
160  * 插入函數,注意插入結點與其在樹中對應的父結點的連接(須要記錄父結點)。
161  * 從根結點出發,不停用當前結點與插入的值比較,若是當前結點的值比較大就往當前結點的左兒子走,相反就往右兒子走,直到當前結點爲空,
162  * 在過程當中記錄當前結點的父結點。
163  * 運行時間爲O(h),h爲樹的高度。由於整個過程是一條沿着根結點降低的路徑。
164  */
165 void RB_Insert(RB_Tree *T, int key){
166     RB_TreeNode *z;
167     z = (RB_TreeNode *)malloc(sizeof(RB_TreeNode));         //新建結點
168     z->value = key;
169     z->color = RED;
170     z->parent = z->left = z->right = NIL;
171     z->size = 1;
172     RB_TreeNode *x = T->root;
173     RB_TreeNode *y = NIL;
174     while(x != NIL){
175         y = x;
176         x->size += 1;
177         if(x->value < key)
178             x = x->right;
179         else
180             x = x->left;
181     }
182     z->parent = y;
183     if(y == NIL){
184         T->root = z;
185         T->root->parent = NIL;
186         T->root->parent->color = BLACK;
187         T->root->size = 1;
188     }
189     else if(z->value < y->value)
190         y->left = z;
191     else
192         y->right = z;
193     RB_Insert_Fixup(T, z);                                 //插入調整,維持紅黑性質
194 }
195 
196 /*
197  * 插入調整,維持紅黑性質
198  */
199 void RB_Insert_Fixup(RB_Tree *T, RB_TreeNode *z){
200     while(z->parent->color == RED){                         //若是z結點的父結點爲黑色,就不用進入3種狀況的處理
201         if(z->parent == z->parent->parent ->left){          //z的父結點爲左兒子的狀況
202             RB_TreeNode *y = z->parent->parent->right;
203             if(y->color == RED){                            //狀況1
204                 z->parent->color = BLACK;
205                 y->color = BLACK;
206                 z->parent->parent->color = RED;
207                 z = z->parent->parent;
208             }                                           
209             else {
210                 if(z == z->parent->right){                  //狀況2
211                     z = z->parent;
212                     Left_Rotate(T, z);                      //左旋轉,狀況2變爲3
213                 }
214                 z->parent->color = BLACK;                   //狀況3
215                 z->parent->parent->color = RED;
216                 Right_Rotate(T, z->parent->parent);         //右選擇解決違反性質4
217             }
218         }
219         else{
220             RB_TreeNode *y = z->parent->parent->left;       //z的結點爲右兒子的狀況
221             if(y->color == RED){                            //狀況1
222                 z->parent->color = BLACK;
223                 y->color = BLACK;
224                 z->parent->parent->color = RED;
225                 z = z->parent->parent;
226             }
227             else{
228                 if(z == z->parent->left){                   //狀況2
229                     z = z->parent;
230                     Right_Rotate(T, z);                     //右旋轉,狀況2變爲狀況3
231                 }
232                 z->parent->color = BLACK;                   //狀況3
233                 z->parent->parent->color = RED;
234                 Left_Rotate(T, z->parent->parent);          //左旋轉解決違反性質4
235             }
236         }
237     }
238     T->root->color = BLACK;                                 //若是紅黑樹T的根結點爲紅色就會變成黑色,若是是黑色變成黑色也沒影響
239 }
240 
241 /*
242  * 刪除結點函數,首先要肯定真正刪除的結點是那個。
243  * 若是z沒有子結點,直接將z的父結點對應的指針指向NULL
244  * 若是z只有一個子節點,直接將z的父結點對應的指針指向z的子結點
245  * 若是z有兩個子結點,實際上要刪除的不是z,而是z的後繼,,再用z的後繼的內容代替z的內容
246  */
247 
248 void RB_Delete(RB_Tree *T, RB_TreeNode *z){
249     RB_TreeNode *x = NULL;
250     RB_TreeNode *y = NULL;
251     RB_TreeNode *p = NULL;
252 
253     if(z->left == NIL || z->right == NIL)
254         y = z;
255     else
256         y = RB_Tree_Successor(z);
257     if(y->left != NIL)
258         x = y->left;
259     else
260         x = y->right;
261     x->parent = y->parent;
262     if(y->parent == NIL)
263         T->root = x;
264     else if(y == y->parent->left)
265         y->parent->left = x;
266     else
267         y->parent->right = x;
268    
269     /* 從刪除結點遍歷一條路徑到根結點,並減小size值*/ 
270     p = y;
271     while(p != T->root){
272         p->parent->size = p->parent->size - 1;
273         p = p->parent;
274     }
275 
276     if(y != z)
277         z->value = y->value;
278     if(y->color == BLACK)
279         RB_Delete_Fixup(T, x);          //當實際要刪除的結點y爲黑色時才須要進行調整
280 }
281 
282 /*
283  * 刪除調整,使紅黑樹維持紅黑性質
284  */
285 void RB_Delete_Fixup(RB_Tree *T, RB_TreeNode *x){
286     
287     /*
288     RB_TreeNode *p = x;
289     while(p != T->root){
290         p->parent->size = p->parent->size - 1;
291         p = p->parent;
292     }
293     */
294     while(x != T->root && x->color == BLACK){               //當x結點爲根結點或者x的顏色爲紅色(即爲紅黑, 實際上額外黑色沒有直接加上去,只是默認x節點有一重額外的黑色)
295         if(x == x->parent->left){                           //x爲左兒子狀況
296             RB_TreeNode *w = x->parent->right;
297             if(w->color == RED){                            //狀況1
298                 w->color = BLACK;
299                 x->parent->color = RED;
300                 Left_Rotate(T, x->parent);                  //左旋轉,使得狀況1轉換成狀況二、3或4
301                 w = x->parent->right;                       
302             }
303             
304             if(w->left->color == BLACK && w->right->color == BLACK){      //狀況2
305                  w->color = RED;                            //修改顏色
306                  x = x->parent;                             //上移
307             }
308             else{
309                 if(w->right->color == BLACK){               //狀況3
310                     w->left->color = BLACK;
311                     w->color = RED;
312                     Right_Rotate(T, w);                     //右旋轉,狀況3轉換成狀況4
313                     w = x->parent->right;
314                 }
315                 w->color = x->parent->color;
316                 x->parent->color = BLACK;
317                 w->right->color = BLACK;
318                 Left_Rotate(T, x->parent);                  //左旋轉,去掉x的額外黑色
319                 x = T->root;                                //使循環結束
320             }
321             
322         }
323         else{                                               //x爲右兒子狀況(PS:下文的註釋參考上文)
324             RB_TreeNode *w = x->parent->left;
325             if(w->color == RED){
326                 w->color = BLACK;
327                 x->parent->color = RED;
328                 Right_Rotate(T, x->parent);
329                 w = x->parent->left;
330             }
331             
332             if(w->left->color == BLACK && w->right->color == BLACK){
333                 w->color = RED;
334                 x = x->parent;
335             }
336             else {
337                 if(w->left->color == BLACK){
338                     w->right->color = BLACK;
339                     w->color = RED;
340                     Left_Rotate(T, w);
341                     w = x->parent->left;
342                 }
343                 w->color = x->parent->color;
344                 x->parent->color = BLACK;
345                 w->left->color = BLACK;
346                 Right_Rotate(T, x->parent);
347                 x = T->root;
348             }
349         }
350     }
351 }
352 
353 
354 RB_TreeNode * RB_Search(RB_TreeNode *x, int key){
355     if(x->value == key || x == NIL)
356         return x;
357     if(x->value > key)
358         RB_Search(x->left, key);
359     else
360         RB_Search(x->right, key);
361 }
362 
363 RB_TreeNode * RB_Tree_Minimum(RB_TreeNode *x){
364     RB_TreeNode *r = x;
365     while(r->left != NIL)
366         r = r->left;
367     return r;
368 }
369 
370 RB_TreeNode * RB_Tree_Maximum(RB_TreeNode *x){
371     RB_TreeNode *r = x;
372     while(r->left != NIL)
373         r = r->left;
374     return r;
375 }
376 
377 RB_TreeNode * RB_Tree_Successor(RB_TreeNode *x){
378     RB_TreeNode *r = x;
379     if(r->right != NIL)
380         return RB_Tree_Minimum(r->right);
381     RB_TreeNode *y = r->parent;
382     while(y != NIL && r == y->right){
383         r = y;
384         y = y->parent;
385     }
386     return y;
387 }
388 RB_TreeNode * RB_Tree_Predecesor(RB_TreeNode *x){
389     RB_TreeNode *r = x;
390     if(r->left != NIL)
391         return RB_Tree_Maximum(r->left);
392     RB_TreeNode *y = r->parent;
393     while(y != NIL && r == y->left){
394         r = y;
395         y = y->parent;
396     }
397     return y;
398 }
399 
400 void Inorder_RB_Tree_Walk(RB_TreeNode *x){
401     if(x != NIL){
402         Inorder_RB_Tree_Walk(x->left);
403         printf("%d : ", x->value);
404         if(x->color == 1)
405             printf("red ");
406         else
407             printf("black ");
408         printf("pos(%d) ", x->size);
409         Inorder_RB_Tree_Walk(x->right);
410     }
411 }
412 
413 void free_men(RB_TreeNode *x){
414     if(x != NIL){
415         free_men(x->left);
416         free_men(x->right);
417         free(x);
418     }
419 }
420 
421 RB_TreeNode * os_select(RB_TreeNode *x, int i){
422     int r = x->left->size + 1;
423     if(i == r)
424         return x;
425     else if(i < r){
426         return os_select(x->left, i);
427     }
428     else{
429         return os_select(x->right, i-r);
430     }
431 }
432 
433 int os_rank(RB_Tree *T, RB_TreeNode *x){
434     int r = x->left->size + 1;
435     RB_TreeNode *y = x;
436     while(y != T->root){
437         if(y == y->parent->right){
438             r += (y->parent->left->size + 1);
439         }
440         y = y->parent;
441     }
442     return r;
443 }
View Code

 

測試結果:

lancelot@debian:~/Code/CLRS/Chapter14$ ./a.out 
10
7 3 9 8 2 6 4 10 5 1
7 : black pos(1) 
3 : red pos(1) 7 : black pos(2) 
3 : red pos(1) 7 : black pos(3) 9 : red pos(1) 
3 : black pos(1) 7 : black pos(4) 8 : red pos(1) 9 : black pos(2) 
2 : red pos(1) 3 : black pos(2) 7 : black pos(5) 8 : red pos(1) 9 : black pos(2) 
2 : red pos(1) 3 : black pos(3) 6 : red pos(1) 7 : black pos(6) 8 : red pos(1) 9 : black pos(2) 
2 : black pos(1) 3 : red pos(4) 4 : red pos(1) 6 : black pos(2) 7 : black pos(7) 8 : red pos(1) 9 : black pos(2) 
2 : black pos(1) 3 : red pos(4) 4 : red pos(1) 6 : black pos(2) 7 : black pos(8) 8 : red pos(1) 9 : black pos(3) 10 : red pos(1) 
2 : black pos(1) 3 : red pos(5) 4 : red pos(1) 5 : black pos(3) 6 : red pos(1) 7 : black pos(9) 8 : red pos(1) 9 : black pos(3) 10 : red pos(1) 
1 : red pos(1) 2 : black pos(2) 3 : red pos(6) 4 : red pos(1) 5 : black pos(3) 6 : red pos(1) 7 : black pos(10) 8 : red pos(1) 9 : black pos(3) 10 : red pos(1) 
3 is exists!
1 : red pos(1) 2 : black pos(2) 3 : red pos(6) 4 : red pos(1) 5 : black pos(3) 6 : red pos(1) 7 : black pos(10) 8 : red pos(1) 9 : black pos(3) 10 : red pos(1) 
3
3
1 : red pos(1) 2 : black pos(2) 4 : red pos(5) 5 : black pos(2) 6 : red pos(1) 7 : black pos(9) 8 : red pos(1) 9 : black pos(3) 10 : red pos(1) 

 

如何擴張數據結構

1、選擇基礎的數據結構

2、肯定要在基礎數據結構中添加哪些信息(根據須要)

3、驗證可用基礎數據結構上的基礎修改操做來維護新添加的信息

4、設計新的操做

 

-----------------------------------------------------------------往後補上區間樹----------------------------------------

-------------------------------------------吐槽--------------------------------------------------------

斷了幾個月的算法導論學習記錄終於又要繼續,以前想只把接下來的看看就算了,可是隻是看看總是以爲學得很差,因此仍是繼續填坑算了

還有不少內容沒啃透。。。。。。。。。。。。。慢慢一步一步學。。。。。。。。。。。。。。。。

算法導論的博客能更新真真真真是很開心。。。。Go on fighting!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

---------------------------------------------------------------------------------------------------------

相關文章
相關標籤/搜索