演算法導論-14.3-6-MIN-GAP

來源:互聯網
上載者:User
一、題目

請說明如何維護一個支援操作MIN-GAP的動態資料集Q,使得該操作能夠給出Q中兩個數之間的最小差幅。例如,Q={1,5,9,15,18,22},則MIN-GAP(Q)返回18-15=3,因為15和18是其中最近的兩個數。使用操作INSERT,DELETE,SEARCH和MIN-GAP儘可能高效,並分析它們的已耗用時間。


二、思考

步驟1:基礎資料結構

紅/黑樹狀結構,數組中的數值分別作為每個結點的關鍵字

步驟2:附加資訊

min-gap[x]:記錄以x為根結點的樹的min-gap。當x為葉子結點時,min-gap[x]=0x7fffffff

min-val[x]:記錄以x為根結點的樹中最小的關鍵字

max-val[x]:記錄以x為根結點的樹中最大的關鍵字

步驟3:對資訊的維護

在插入的刪除的同時,對這三個附加資訊進行更新操作,時間複雜度不改變


步驟4:設計新的操作

Min_Gap():返回根結點的min-gap值

 

三、代碼
#include <iostream>using namespace std;#define BLACK 0#define RED 1//MIN-GAP樹結點結構struct node{node *left;//左孩子node *right;//右孩子node *p;//父int key;//關鍵字bool color;//顏色,紅或黑int min_gap;//記錄以x為根結點的樹的min-gap。當x為葉子結點時,min-gap[x]=0x7fffffffint min_val;//記錄以x為根結點的樹中最小的關鍵字int max_val;//記錄以x為根結點的樹中最大的關鍵字node(node *init, int k):left(init),right(init),p(init),key(k),color(BLACK),min_gap(0x7fffffff),min_val(k),max_val(k){}};//區間樹結構struct Min_Gap_Tree{node *root;//根結點node *nil;//哨兵Min_Gap_Tree(){nil = new node(NULL, -1);root = nil;};};int Min(int a, int b, int c, int d){a = a < b ? a : b;c = c < d ? c : d;return a < c ? a : c;}//對資訊的維護void Maintaining(Min_Gap_Tree *T, node *x){while(x != T->nil){//對min_val資訊的維護x->min_val = (x->left != T->nil) ? x->left->min_val : x->key;//對max_val資訊的維護x->max_val = (x->right != T->nil) ? x->right->max_val : x->key;//對min_gap資訊的維護int a = (x->left != T->nil) ? x->left->min_gap : 0x7fffffff;int b = (x->right != T->nil) ? x->right->min_gap : 0x7fffffff;int c = (x->left != T->nil) ? (x->key - x->left->max_val) : 0x7fffffff;int d = (x->right != T->nil) ? (x->right->min_val - x->key) : 0x7fffffff;x->min_gap = Min(a, b, c, d);//向上更新x = x->p;}}//左旋,令y = x->right, 左旋是以x和y之間的鏈為支軸進行旋轉//涉及到的結點包括:x,y,y->left,令node={p,l,r},具體變化如下://x={x->p,x->left,y}變為{y,x->left,y->left}//y={x,y->left,y->right}變為{x->p,x,y->right}//y->left={y,y->left->left,y->left->right}變為{x,y->left->left,y->left->right}void Left_Rotate(Min_Gap_Tree *T, node *x){//令y = x->rightnode *y = x->right;//按照上面的方式修改三個結點的指標,注意修改指標的順序x->right = y->left;if(y->left != T->nil)y->left->p = x;y->p = x->p;if(x->p == T->nil)//特殊情況:x是根結點T->root = y;else if(x == x->p->left)x->p->left = y;else x->p->right = y;y->left = x;x->p = y;Maintaining(T, x);}//右旋,令y = x->left, 左旋是以x和y之間的鏈為支軸進行旋轉//旋轉過程與上文類似void Right_Rotate(Min_Gap_Tree *T, node *x){node *y = x->left;x->left = y->right;if(y->right != T->nil)y->right->p = x;y->p = x->p;if(x->p == T->nil)T->root = y;else if(x == x->p->right)x->p->right = y;else x->p->left = y;y->right = x;x->p = y;Maintaining(T, x);}//紅/黑樹狀結構調整void MG_Insert_Fixup(Min_Gap_Tree *T, node *z){node *y;//唯一需要調整的情況,就是違反性質2的時候,如果不違反性質2,調整結束while(z->p->color == RED){//p[z]是左孩子時,有三種情況if(z->p == z->p->p->left){//令y是z的叔結點y = z->p->p->right;//第一種情況,z的叔叔y是紅色的if(y->color == RED){//將p[z]和y都著為黑色以解決z和p[z]都是紅色的問題z->p->color = BLACK;y->color = BLACK;//將p[p[z]]著為紅色以保持性質5z->p->p->color = RED;//把p[p[z]]當作新增的結點z來重複while迴圈z = z->p->p;}else{//第二種情況:z的叔叔是黑色的,且z是右孩子if(z == z->p->right){//對p[z]左旋,轉為第三種情況z = z->p;Left_Rotate(T, z);}//第三種情況:z的叔叔是黑色的,且z是左孩子//交換p[z]和p[p[z]]的顏色,並右旋z->p->color = BLACK;z->p->p->color = RED;Right_Rotate(T, z->p->p);}}//p[z]是右孩子時,有三種情況,與上面類似else if(z->p == z->p->p->right){y = z->p->p->left;if(y->color == RED){z->p->color = BLACK;y->color = BLACK;z->p->p->color = RED;z = z->p->p;}else{if(z == z->p->left){z = z->p;Right_Rotate(T, z);}z->p->color = BLACK;z->p->p->color = RED;Left_Rotate(T, z->p->p);}}}//根結點置為黑色T->root->color = BLACK;}//插入一個結點void Min_Gap_Insert(Min_Gap_Tree *T, node *z){node *y = T->nil, *x = T->root;//找到應該插入的位置,與二叉尋找樹的插入相同while(x != T->nil){y = x;if(z->key < x->key)x = x->left;elsex = x->right;}z->p = y;if(y == T->nil)T->root = z;else if(z->key < y->key)y->left = z;elsey->right = z;z->left = T->nil;z->right = T->nil;//將新插入的結點轉為紅色z->color = RED;//從新插入的結點開始,向上調整MG_Insert_Fixup(T, z);//對資訊的維護Maintaining(T, z);}//對樹進行調整,x指向一個紅黑結點,調整的過程是將額外的黑色沿樹上移void MG_Delete_Fixup(Min_Gap_Tree *T, node *x){node *w;//如果這個額外的黑色在一個根結點或一個紅結點上,結點會吸收額外的黑色,成為一個黑色的結點while(x != T->root && x->color == BLACK){//若x是其父的左結點(右結點的情況相對應)if(x == x->p->left){//令w為x的兄弟,根據w的不同,分為三種情況來處理//執行刪除操作前x肯定是沒有兄弟的,執行刪除操作後x肯定是有兄弟的w = x->p->right;//第一種情況:w是紅色的if(w->color == RED){//改變w和p[x]的顏色w->color = BLACK;x->p->color = RED;//對p[x]進行一次左旋Left_Rotate(T, x->p);//令w為x的新兄弟w = x->p->right;//轉為2.3.4三種情況之一}//第二情況:w為黑色,w的兩個孩子也都是黑色if(w->left->color == BLACK && w->right->color == BLACK){//去掉w和x的黑色//w只有一層黑色,去掉變為紅色,x有多餘的一層黑色,去掉後恢複原來顏色w->color = RED;//在p[x]上補一層黑色x = x->p;//現在新x上有個額外的黑色,轉入for迴圈繼續處理}//第三種情況,w是黑色的,w->left是紅色的,w->right是黑色的else{if(w->right->color == BLACK){//改變w和left[x]的顏色w->left->color = BLACK;w->color = RED;//對w進行一次右旋Right_Rotate(T, w);//令w為x的新兄弟w = x->p->right;//此時轉變為第四種情況}//第四種情況:w是黑色的,w->left是黑色的,w->right是紅色的//修改w和p[x]的顏色w->color =x->p->color;x->p->color = BLACK;w->right->color = BLACK;//對p[x]進行一次左旋Left_Rotate(T, x->p);//此時調整已經結束,將x置為根結點是為了結束迴圈x = T->root;}}//若x是其父的左結點(右結點的情況相對應)else if(x == x->p->right){//令w為x的兄弟,根據w的不同,分為三種情況來處理//執行刪除操作前x肯定是沒有兄弟的,執行刪除操作後x肯定是有兄弟的w = x->p->left;//第一種情況:w是紅色的if(w->color == RED){//改變w和p[x]的顏色w->color = BLACK;x->p->color = RED;//對p[x]進行一次左旋Right_Rotate(T, x->p);//令w為x的新兄弟w = x->p->left;//轉為2.3.4三種情況之一}//第二情況:w為黑色,w的兩個孩子也都是黑色if(w->right->color == BLACK && w->left->color == BLACK){//去掉w和x的黑色//w只有一層黑色,去掉變為紅色,x有多餘的一層黑色,去掉後恢複原來顏色w->color = RED;//在p[x]上補一層黑色x = x->p;//現在新x上有個額外的黑色,轉入for迴圈繼續處理}//第三種情況,w是黑色的,w->right是紅色的,w->left是黑色的else{if(w->left->color == BLACK){//改變w和right[x]的顏色w->right->color = BLACK;w->color = RED;//對w進行一次右旋Left_Rotate(T, w);//令w為x的新兄弟w = x->p->left;//此時轉變為第四種情況}//第四種情況:w是黑色的,w->right是黑色的,w->left是紅色的//修改w和p[x]的顏色w->color =x->p->color;x->p->color = BLACK;w->left->color = BLACK;//對p[x]進行一次左旋Right_Rotate(T, x->p);//此時調整已經結束,將x置為根結點是為了結束迴圈x = T->root;}}}//吸收了額外的黑色x->color = BLACK;}//找最小值   node *Tree_Minimum(Min_Gap_Tree *T, node *x)  {      //只要有比當前結點小的結點   while(x->left != T->nil)          x = x->left;      return x;  } //尋找中序遍曆下x結點的後繼,後繼是大於key[x]的最小的結點   node *Tree_Successor(Min_Gap_Tree *T, node *x)  {      //如果有右孩子   if(x->right != T->nil)          //右子樹中的最小值           return Tree_Minimum(T, x->right);      //如果x的右子樹為空白且x有後繼y,那麼y是x的最低祖先結點,且y的左兒子也是       node *y = x->p;      while(y != NULL && x == y->right)      {          x = y;          y = y->p;      }      return y;  }   //紅/黑樹狀結構的刪除node *Min_Gap_Delete(Min_Gap_Tree *T, node *z){//找到結點的位置並刪除,這一部分與二叉尋找樹的刪除相同node *x, *y;if(z->left == T->nil || z->right == T->nil)y = z;else y = Tree_Successor(T, z);if(y->left != T->nil)x = y->left;else x = y->right;x->p = y->p;if(y->p == T->nil)T->root = x;else if(y == y->p->left)y->p->left = x;elsey->p->right = x;//對資訊的維護Maintaining(T, x);if(y != z){z->key = y->key;//對資訊的維護Maintaining(T, z);}//如果被刪除的結點是黑色的,則需要調整if(y->color == BLACK)MG_Delete_Fixup(T, x);return y;}//遞迴地查詢二叉尋找樹     node *Min_Gap_Search(node *x, int k)    {        //找到葉子結點了還沒找到,或當前結點是所尋找的結點         if(x->key == -1 || k == x->key)            return x;        //所尋找的結點位於當前結點的左子樹         if(k < x->key)            return Min_Gap_Search(x->left, k);        //所尋找的結點位於當前結點的左子樹         else            return Min_Gap_Search(x->right, k);    }   void Print(node *x){if(x->key == -1)return;Print(x->left);cout<<x->key<<' '<<x->color<<endl;Print(x->right);}int Min_Gap(node *r){return r->min_gap;}void Print(Min_Gap_Tree *T){Print(T->root);cout<<endl;}int main(){//產生一棵MIN-GAP樹Min_Gap_Tree *T = new Min_Gap_Tree;int x;char ch;while(1){cout<<"請輸入一個操作:"<<endl;cout<<"I:插入一個隨機數到集合中"<<endl;cout<<"D x:從集合中刪除一個值為x的數"<<endl;cin>>ch;switch (ch){//插入一個關鍵字case 'I':{//產生一個待插入的隨機數x = rand() % 100;//顯示剛剛插入的數cout<<"插入的數字是"<<x<<endl;node *z = new node(T->nil, x);Min_Gap_Insert(T, z);//輸出min-gapcout<<"min-gap = "<<Min_Gap(T->root)<<endl;break;}//刪除一個關鍵字case 'D':{//輸入待刪除的數cin>>x;//先從集合中找到值為x的數node *ret = Min_Gap_Search(T->root, x);//集合中有這個數,則刪除,沒有則不處理if(ret == T->nil)cout<<"not exist"<<endl;elseMin_Gap_Delete(T, ret);//輸出min-gapcout<<"min-gap = "<<Min_Gap(T->root)<<endl;break;}}cout<<endl;}return 0;}
四、測試代碼

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.