《算法導論》學習記錄目錄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 }
測試結果:
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!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
---------------------------------------------------------------------------------------------------------