算法导论 动态顺序统计与区间树

  • 本文的基础是红黑树 算法导论–红黑树

    通过在基础的数据结构中添加一些附加信息,来扩张一种标准的数据结构,然后编写新的操作来支持所需要的应用。下面是介绍在红黑树的基础上扩张的数据结构。

    1.动态顺序统计

    动态顺序统计可以在O(lgn)时间内确定任何的顺序统计量(即在n个元素的集合中,能在O(lgn)的时间内确定第i小的元素),同时也可以在O(lgn)的时间内计算一个元素的秩(即它在中序遍历下的位置顺序)。

    添加附加信息

    结点x中加入x.size , size的大小为以x为根的子树(包含x本身)的内结数,即子树的大小。我们定义哨兵的size为0,如下图: 
    \ 
    结点内,虚线上方为关键字key,下方为结点的size。 
    可以看出: x.size = x.left.size + x.right.size +1;

    01. <code class=" hljs d">enum colors{red,black};//枚举类型
    02. typedef struct Node
    03. {
    04. struct Node * p;
    05. struct Node *left;
    06. struct Node *right;
    07. int key;            
    08. enum  colors color;  //颜色属性
    09. int size;           //新添加的属性size
    10. }Node;</code>
    修改基本操作

    插入操作: 
    为了对子树规模的维护,需要在不影响插入和删除操作的渐进运行时间的前提下,修改基本的操作。 
    第一阶段:新节点的插入过程中,需要对从根到将要插入的位置过程中遍历的结点的size加1; 
    第二阶段:维护红黑树的左旋和右旋函数需要在最后添加以下语句: 
    \

    1. <code class=" hljs avrasm"/*左旋*/
    2. y.size = x.size;
    3. x.size = x.left.size + x.right.size +1;
    4. /*右旋*/
    5. x.size = y.size;
    6. y.size = y.left.size + y.right.size +1;</code>

    删除操作: 
    第一阶段:如果要删除的结点z少于两个孩子,则从z到根T的过程遍历的结点size减1;如果要删除的结点z多于两个孩子,则从z的后继y处向上到T的过程中,遍历的结点size减1; 
    第二阶段: 
    也是同样在左右旋过程中,添加以上的语句; 
    插入操作和删除操作运行时间都是O(lgn).

    设计新的操作

    1.给定秩的元素的检索 
    调用函数OS_Select(Node * x,int i)检索出在以x为根的子树中,第i小的关键字的结点。运行时间为O(lgn);

    01. <code class=" hljs lasso">Node * OS_Select(Node *x,int i)
    02. {
    03. int r =x->left->size+1;           //计算以结点x为根的子树中顺序统计量r
    04. if (i == r)
    05. return x;  
    06. else if (i < r)               
    07. return OS_Select(x->left,i);  //在x的左子树里继续递归查找
    08. else
    09. return OS_Select(x->right,i-r);//在x的右子树里继续递归查找
    10. }</code>

    2.确定一个元素的秩 
    给定指向T中,结点x的指针,过程OS_Rank返回对T中序遍历对应的线性序中x的位置;运行时间为O(lgn)

    01. <code class=" hljs lasso">int OS_Rank(Node *T,Node * x)
    02. {
    03. int r =x->left->size+1;  //计算以结点x为根的子树中顺序统计量r
    04. Node * y =x;
    05. while(y != T)                 //叠加到root根节点位置
    06. {
    07. if (y == y->p->right)          //父节点的右子树输出在左子树和根之后,顺序统计量叠加
    08. {
    09. r=r+y->p->left->size+1;
    10. }
    11. y = y->p;                      //若属于左子树,直接跳向上层
    12. }
    13. return r;
    14. }</code>
    完整代码
    001. <code class=" hljs haskell">/*       
    002. CSDN 勿在浮砂筑高台
    004. 算法导论--顺序统计量
    005. 2015年5月20日
    006. */
    007. #include <STDIO.H>
    008. #include <STDLIB.H>
    009. enum colors{red,black};//枚举类型
    010. typedef struct Node
    011. {
    012. struct Node * p;
    013. struct Node *left;
    014. struct Node *right;
    015. int key;
    016. enum  colors color;
    017. int size;                       //添加附加信息size
    018. }Node;
    019. Node *T_NIL=NULL;                 //建立全部变量 T_NIL
    020.  
    021. Node * Tree_Minimum(Node * T)     //找最小结点
    022. {
    023. while(T->left != T_NIL)
    024. T=T->left;
    025. return T;
    026. }
    027. void Inorder_Tree_Walk(Node * T)  //中序遍历树T,输出
    028. {
    029. if ( T != T_NIL)
    030. {
    031. Inorder_Tree_Walk(T->left);   //递归其左孩子
    032. printf("%d",T->key);        //输出根的关键字
    033. if (T->color == 0)
    034. {
    035. printf("-R");
    036. }
    037. else
    038. {
    039. printf("-B");
    040. }
    041. printf("-(%d)  ",T->size);
    042. Inorder_Tree_Walk(T->right);  //递归其右孩子
    043. }
    044. }
    045. void Pre_Tree_Walk(Node * T)  //
    046. {
    047. if ( T != T_NIL)
    048. {    
    049. printf("%d    ",T->key);          //输出根的关键字
    050. Pre_Tree_Walk(T->left);   //递归其左孩子     
    051. Pre_Tree_Walk(T->right);  //递归其右孩子
    052.  
    053. }
    054. }
    055.  
    056. void Left_Rotate(Node **T,Node * x)   //左旋
    057. {
    058. Node *y=x->right;
    059.  
    060. x->right =y->left;
    061. if (y->left != T_NIL)
    062. y->left->p=x;
    063. y->p=x->p;
    064. if(x->p==T_NIL)
    065. *T=y;
    066. else if (x == x->p->left)
    067. x->p->left = y;
    068. else
    069. x->p->right = y;
    070. y->left = x;
    071. x->p=y;
    072.  
    073. y->size = x->size;                         //添加语句维护size
    074. x->size = x->left->size+x->right->size+1;
    075. }
    076. void Right_Rotate(Node **T,Node * y)   //右旋
    077. {
    078. Node *x=y->left;
    079.  
    080. y->left =x->right;
    081. if (x->right != T_NIL)
    082. x->right->p=y;
    083. x->p=y->p;
    084. if(y->p==T_NIL)
    085. *T=x;
    086. else if (y == y->p->left)
    087. y->p->left = x;
    088. else 
    089. y->p->right = x;
    090. x->right = y;
    091. y->p=x;
    092.  
    093. x->size = y->size;                     //添加语句维护size
    094. y->size = y->left->size+y->right->size+1;
    095. }
    096. Node* RB_Insert_Fixup(Node *T,Node *z)
    097. {
    098. Node * y=NULL;
    099. while( z->p->color == red)       //违反了性质4,迭代进行修正
    100. {
    101. if (z->p == z->p->p->left)
    102. {
    103. y = z->p->p->right;
    104. if ( y->color == red)    // case 1 叔结点为红色
    105. {
    106. z->p->color = black;    //父节点涂黑
    107. y->color = black;       //叔结点涂黑
    108. z->p->p->color = red;   //祖结点涂红
    109. z = z->p->p;            //向上迭代,更新z的位置
    110. }
    111. else if ( z == z->p->right) //case 2 叔结点为黑色且z为双亲的右孩子
    112. {
    113. z = z->p;
    114. Left_Rotate(&T,z);
    115. z->p->color = black;    //case2 已转为 case3 继续处理
    116. z->p->p->color = red;
    117. Right_Rotate(&T,z->p->p);// while循环终止
    118. }
    119. else                      // case 3 叔结点为黑色且z为双亲的左孩子
    120. {
    121. z->p->color = black;
    122. z->p->p->color = red;
    123. Right_Rotate(&T,z->p->p);//   while循环终止
    124. }
    125. }
    126.  
    127. else                      //对称处理
    128. {
    129.  
    130. y = z->p->p->left;
    131. if ( y->color == red)    // case 1 叔结点为红色
    132. {
    133. z->p->color = black;
    134. y->color = black;
    135. z->p->p->color = red;
    136. z = z->p->p;
    137. }
    138.  
    139. else if ( z == z->p->left) //case 2 叔结点为黑色且z为双亲的右孩子
    140. {
    141. z = z->p;
    142. Right_Rotate(&T,z);
    143. z->p->color = black;
    144. z->p->p->color = red;
    145. Left_Rotate(&T,z->p->p);//
    146. }
    147. else                      // case 3
    148. {
    149. z->p->color = black;
    150. z->p->p->color = red;
    151. Left_Rotate(&T,z->p->p);
    152. }
    153.  
    154.
    155. }
    156.  
    157. T->color = black;          //保证不会违反性质2,对根节点涂黑
    158. return T;
    159. }
    160. Node *RB_Insert(Node *Root,Node * z)   //红黑树插入,返回树的根
    161. {
    162. Node * y=T_NIL;
    163. Node * x=Root;
    164. while( x != T_NIL)                 //找到结点z要插入的位置   
    165. {
    166. x->size+=1;                    //插入过程中,遍历的结点size加1
    167.  
    168. y=x;
    169. if (z->key < x->key)
    170. x = x->left;
    171. else
    172. x = x->right;
    173. }
    174. z->p = y;
    175. if ( y == T_NIL)    //插入第一个结点作为根节点的情况 
    176. Root = z;
    177. else if (z->key < y->key)
    178. y->left = z;
    179. else   
    180. y->right = z;
    181.  
    182. Root = RB_Insert_Fixup(Root,z);    //插入完毕后,对红黑树的颜色进行修正
    183. return Root;
    184. }
    185. Node * Establish(int *A,int len)   //建立红黑树
    186. {
    187. Node * T,*node;
    188. int i=0;
    189. node=NULL;
    190. T_NIL=(Node *)malloc(sizeof(Node));  //建立T_NIL结点
    191. T_NIL->p=NULL;
    192. T_NIL->left=NULL;
    193. T_NIL->right=NULL;
    194. T_NIL->key=-1;
    195. T_NIL->color=black;
    196. T_NIL->size=0;
    197. T=T_NIL;
    198. for (i=0;i<len;i++)
    199. {
    200. node =(Node *)malloc(sizeof(Node));
    201. node->p =T_NIL;
    202. node->left=T_NIL;
    203. node->right=T_NIL;
    204. node->key=A[i];
    205. node->color=red;
    206. node->size=1;
    207. T=RB_Insert(T,node);
    208. }
    209. return T;
    210. }
    211.  
    212. void RB_Transplant(Node **T,Node * u,Node * v)  //结点替代函数
    213. {
    214. if (u->p == T_NIL)
    215. *T = v;
    216. else if (u == u->p->left)
    217. u->p->left = v;
    218. else
    219. u->p->right = v;
    220. v->p = u->p;               //此处赋值无条件,v如果是T_NIL也要进行赋值
    221. }
    222. void RB_Delete_Fixup(Node * T,Node * x)
    223. {
    224. Node *w=NULL;
    225. while( x != T && x->color == black)      //循环迭代处理
    226. {
    227. if ( x == x->p->left )
    228. {
    229. w = x->p->right;
    230. if (w->color == red)             // case 1 ------> case 2 , case 3 ,case 4
    231. {
    232. w->color = black;
    233. x->p->color =red;
    234. Left_Rotate(&T,x->p);
    235. w = x->p->right;
    236. }
    237. if ( w->left->color == black && w->right->color == black ) //case 2 ------>go on / stop
    238. {
    239. w->color = red;
    240. x = x->p;
    241. }
    242. else if ( w->right->color == black)   // case 3 ---->case 4---->stop
    243. {
    244. w->left->color = black;
    245. w->color =red ;
    246. Right_Rotate(&T,w);
    247.  
    248. w = x->p->right ;                   //转成case 4处理
    249. w->color = x->p->color;
    250. x->p->color = black;
    251. w->right->color = black;
    252. Left_Rotate(&T,x->p);
    253. x = T;
    254. }
    255. else                               // case 4 ------------------->stop
    256. {
    257. w->color = x->p->color;
    258. x->p->color = black;
    259. w->right->color = black;
    260. Left_Rotate(&T,x->p);
    261. x = T;
    262. }
    263. }
    264. else
    265. {
    266. w = x->p->left;
    267. if (w->color == red)                // case 1 ------> case 2 , case 3 ,case 4
    268. {
    269. w->color = black;
    270. x->p->color =red;
    271. Right_Rotate(&T,x->p);
    272. w = x->p->left;
    273. }
    274. if ( w->right->color == black && w->left->color == black ) //case 2 ------>go on/stop
    275. {
    276. w->color = red;
    277. x = x->p;
    278. }
    279. else if ( w->left->color == black)      // case 3 -----> case 4----->stop
    280. {
    281. w->right->color = black;
    282. w->color =red ;
    283. Left_Rotate(&T,w);
    284.  
    285. w = x->p->left ;                    //转成case 4处理
    286. w->color = x->p->color;
    287. x->p->color = black;
    288. w->left->color = black;
    289. Right_Rotate(&T,x->p);
    290. x = T;
    291. }
    292. else                                  // case 4 -------------->stop
    293. {
    294. w->color = x->p->color;
    295. x->p->color = black;
    296. w->left->color = black;
    297. Right_Rotate(&T,x->p);
    298. x = T;
    299. }
    300. }
    301. }
    302.  
    303. x->color = black;                       //可能由case2退出,那把x涂黑即可,见分析!也可能有case4退出,把根节点涂黑
    304. }
    305. Node * RB_Delete(Node *T ,Node *z)
    306. {
    307.  
    308. Node * x =NULL;
    309. Node * y =z;
    310. Node *temp=y->p;
    311. enum colors y_original_color = y->color;   //记录下删除前z的颜色
    312. if ( z->left == T_NIL)                     //左子树不存在的情况 
    313. {
    314. x = z->right;
    315. RB_Transplant(&T,z,z->right);
    316. }
    317. else if ( z->right == T_NIL)              //右子树不存在
    318. {
    319. x = z->left;
    320. RB_Transplant(&T,z,z->left);
    321. }
    322. else                                     //左右都存在的情况
    323. {
    324. y = Tree_Minimum(z->right);            //找到后继y
    325. temp=y->p;  
    326. y_original_color = y->color;           //记录下y转移前的颜色
    327. x = y->right;
    328. if ( y->p == z)                       //如果y是z的子结点
    329. {
    330. x->p = y;
    331. }
    332. else
    333. {
    334. RB_Transplant(&T,y,y->right);    //如果y不是z的子结点,用y的右子树代替y的位置
    335. y->right = z->right;
    336. y->right->p = y;
    337. }
    338. RB_Transplant(&T,z,y);           //y替代z的位置 ,不论y是不是T_NIL  
    339. y->left = z->left;
    340. y->left->p = y;
    341. y->color = z->color;             //把y的颜色改成z的颜色
    342.  
    343. y->size =y->left->size+y->right->size+1;
    344. }
    345.  
    346. while(temp != T_NIL)             //从删除的位置或后继的位置向上遍历size--,直到根节点为止
    347. {
    348. temp->size--;
    349. temp = temp->p;
    350. }
    351.  
    352.  
    353.  
    354. if ( y_original_color == black)   //判断y的颜色,若为黑色,需要修复
    355. RB_Delete_Fixup(T,x);
    356. return T;
    357. }
    358.  
    359. Node * Tree_Search(Node *T ,int k)  //寻找数k是否在树中,且返回数k的地址
    360. {  
    361.  
    362. while(T !=T_NIL && T->key != k)
    363. {
    364. if ( k < T->key)
    365. T=T->left;
    366. else
    367. T=T->right;
    368. }
    369.  
    370. if ( T == T_NIL)
    371. {    
    372. return NULL;
    373. }
    374.  
    375. else
    376. {
    377. return T;
    378. }
    379.  
    380. }
    381. Node * OS_Select(Node *x,int i)        //确定以x为根节点的子树,第i小的关键字
    382. {
    383. int r =x->left->size+1;
    384. if (i == r)
    385. return x;  
    386. else if (i < r)
    387. return OS_Select(x->left,i);
    388. else
    389. return OS_Select(x->right,i-r);
    390. }
    391. int OS_Rank(Node *T,Node * x)         //确定x在树T中序遍历中的位置顺序
    392. {
    393. int r =x->left->size+1;
    394. Node * y =x;
    395. while(y != T)
    396. {
    397. if (y == y->p->right)
    398. {
    399. r=r+y->p->left->size+1;
    400. }
    401. y = y->p;
    402. }
    403. return r;
    404. }
    405. void main()
    406. {
    407. int A[]={2,5,1,6,3,8,4,9,7};
    408.  
    409. int length = sizeof(A)/sizeof(A[0]); //数组A的长度
    410. Node *T =Establish(A,length);        //建立红黑树,返回根节点T
    411.  
    412. printf("中序遍历:\n");
    413. Inorder_Tree_Walk(T);printf("\n");   //中序遍历输出
    414.  
    415. printf("先序遍历:\n");              //先序遍历输出
    416. Pre_Tree_Walk(T);printf("\n");
    417.  
    418. printf("__%d__\n",OS_Select(T,5)->key);
    419. printf("--%d--\n",OS_Rank(T,Tree_Search(T,3)));
    420.  
    421. printf("-----------删除操作后-------------\n");
    422.  
    423. T=RB_Delete(T,Tree_Search(T,2));
    424. T=RB_Delete(T,Tree_Search(T,5));
    425. T=RB_Delete(T,Tree_Search(T,7));
    426. T=RB_Delete(T,Tree_Search(T,4));
    427. printf("中序遍历:\n");
    428. Inorder_Tree_Walk(T);
    429. printf("\n");
    430.  
    431. printf("先序遍历:\n");
    432. Pre_Tree_Walk(T);
    433.  
    434. printf("\n");
    435. }</code>

    2.区间树

    区间树是通过扩张红黑树来构成由区间构成的动态集合。结点的属性由一个关键字key变成了一个区间。 
    \

    1.添加附加信息

    添加区间信息INT,INT结构包含区间的左右端点。还包含Max属性,它是以自身为根的子树中所有的区间的端点最大值。(上图中虚线下方)

    01. <code class=" hljs d">enum colors{red,black};//枚举类型
    02. struct Interval //区间
    03. {
    04. int low;
    05. int high;
    06. };
    07. typedef struct Node
    08. {
    09. struct Node * p;
    10. struct Node *left;
    11. struct Node *right;
    12. enum  colors color;
    13. //添加的属性
    14. struct Interval INT;   //存储结点区间信息                  
    15. int  Max;              //以结点为根的所有区间端点的最大值     
    16. }Node;</code>
    2.修改基本操作

    修改红黑树的插入和删除操作维添加的信息,都能保证在O(lgn)的时间内完成; 
    1.插入操作: 
    第一步:由于区间树采用区间左端点作为关键字进行插入,遍历时通过比较INT.low的方式插入;插入前令Max=high,插入时从根节点开始遍历到要插入的位置,把遍历的结点的Max与新添加的结点z的Max进行比较,如果z.Max>x.Max ,更新结点的x.Max=z.Max

    01. <code class=" hljs lasso">Node *Interval_Insert(Node *Root,Node * z)   //红黑树插入,返回树的根
    02. {
    03. Node * y=T_NIL;
    04. Node * x=Root;
    05. while( x != T_NIL)                 //找到结点z要插入的位置   
    06. {
    07. if ( z->Max > x->Max)     //比较新插入的结点z与结点x的Max大小;
    08. {
    09. x->Max = z->Max;
    10. }
    11. y=x;
    12. if (z->INT.low < x->INT.low)
    13. x = x->left;
    14. else
    15. x = x->right;
    16. }
    17. z->p = y;
    18. if ( y == T_NIL)    //插入第一个结点作为根节点的情况 
    19. Root = z;
    20. else if (z->INT.low < y->INT.low)
    21. y->left = z;
    22. else   
    23. y->right = z;
    24.  
    25. Root = Interval_Insert_Fixup(Root,z);    //插入完毕后,对红黑树的颜色进行修正
    26. return Root;
    27. }</code>

    第二步:由于左旋右旋会破坏区间的性质,在函数代码后添加更新信息

    01. <code class=" hljs lasso">void Left_Rotate(Node **T,Node * x)   //左旋
    02. {
    03. Node *y=x->right;
    04.  
    05. x->right =y->left;
    06. if (y->left != T_NIL)
    07. y->left->p=x;
    08. y->p=x->p;
    09. if(x->p==T_NIL)
    10. *T=y;
    11. else if (x == x->p->left)
    12. x->p->left = y;
    13. else
    14. x->p->right = y;
    15. y->left = x;
    16. x->p=y;
    17.  
    18. y->Max = x->Max;                         //添加语句维护Max
    19. x->Max = GetMax(x->left->Max,x->right->Max,x->INT.high);
    20. }
    21. void Right_Rotate(Node **T,Node * y)   //右旋
    22. {
    23. Node *x=y->left;
    24.  
    25. y->left =x->right;
    26. if (x->right != T_NIL)
    27. x->right->p=y;
    28. x->p=y->p;
    29. if(y->p==T_NIL)
    30. *T=x;
    31. else if (y == y->p->left)
    32. y->p->left = x;
    33. else 
    34. y->p->right = x;
    35. x->right = y;
    36. y->p=x;
    37.  
    38. x->Max = y->Max;                         //添加语句维护Max
    39. y->Max = GetMax(y->left->Max,y->right->Max,y->INT.high);
    40. }</code>

    2.删除操作

    第一步:被删除的结点z可能会影响整个区间树的性质,如果结点z少于两个孩子,则沿着z上升到根节点为止,对树重新更新维护;如果有两个孩子则从后继出发,进行维护;

    1. <code class=" hljs lasso">while( temp != T_NIL )             //从要删除的结点或其后继开始向上修复区间树
    2. {      
    3. temp->Max = GetMax(temp->left->Max,temp->right->Max,temp->INT.high);
    4. temp = temp->p;     //每次一层,至多lgn层
    5. }</code>

    第二步:同上,也是在左旋右旋函数后添加代码。

    3.设计新的操作

    判断给定的一个区间i位于区间树的哪个位置。区间之间的关系: 
    \ 
    a重叠的情况;b、c不重叠的情况 
    不重叠的情况用代码表示为

    1. <code class=" hljs haskell">x->INT.high < i->low
    2. x->INT.low  > i->high</code>

    如果存在区间与i重叠则返回结点的位置,否则返回T_NIL

    01. <code class=" hljs lasso">Node * Interval_Search(Node *T ,struct Interval *i)  //寻找数k是否在树中,且返回数k的地址
    02. {  
    03. Node * x = T;
    04. while(x != T_NIL && ((x->INT.high < i->low)||(x->INT.low > i->high)))  //不重叠
    05. {
    06. if (x->left != T_NIL && x->left->Max >= i->low)  //在其左子树中搜索
    07. {
    08. x = x->left;
    09. }
    10. else
    11. {
    12. x = x->right;
    13. }
    14. }
    15.  
    16. return x;
    17. }</code>

    每次迭代都是一层,至多lgn层;所以耗时O(lgn)的时间

    4.完整代码
    001. <code class=" hljs haskell">/*       
    002. CSDN 勿在浮砂筑高台
    004. 算法导论--区间树
    005. 2015年5月20日
    006. */
    007. #include <STDIO.H>
    008. #include <STDLIB.H>
    009. enum colors{red,black};//枚举类型
    010. struct Interval //区间
    011. {
    012. int low;
    013. int high;
    014. };
    015. typedef struct Node
    016. {
    017. struct Node * p;
    018. struct Node *left;
    019. struct Node *right;
    020. enum  colors color;
    021. //添加的属性
    022. struct Interval INT;   //存储结点区间信息                  
    023. int  Max;              //以结点为根的所有区间端点的最大值     
    024. }Node;
    025. Node *T_NIL=NULL;                 //建立全部变量 T_NIL
    026.  
    027. int GetMax(int a,int b,int c)    //返回a,b,c最大值
    028. {
    029. return a>b?(a>c?a:c):(b>c?b:c);
    030. }
    031. Node * Tree_Minimum(Node * T)     //找最小结点
    032. {
    033. while(T->left != T_NIL)
    034. T=T->left;
    035. return T;
    036. }
    037. void Inorder_Tree_Walk(Node * T)  //中序遍历树T,输出
    038. {
    039. if ( T != T_NIL)
    040. {
    041. Inorder_Tree_Walk(T->left);   //递归其左孩子
    042. printf("%d",T->INT.low);        //输出根的关键字
    043. if (T->color == 0)
    044. {
    045. printf("-R(%d)  ",T->Max);
    046. }
    047. else
    048. {
    049. printf("-B(%d)   ",T->Max);
    050. }
    051. Inorder_Tree_Walk(T->right);  //递归其右孩子
    052. }
    053. }
    054. void Pre_Tree_Walk(Node * T)  //
    055. {
    056. if ( T != T_NIL)
    057. {    
    058. printf("%d    ",T->INT.low);          //输出根的关键字
    059. Pre_Tree_Walk(T->left);   //递归其左孩子     
    060. Pre_Tree_Walk(T->right);  //递归其右孩子
    061.  
    062. }
    063. }
    064.  
    065. void Left_Rotate(Node **T,Node * x)   //左旋
    066. {
    067. Node *y=x->right;
    068.  
    069. x->right =y->left;
    070. if (y->left != T_NIL)
    071. y->left->p=x;
    072. y->p=x->p;
    073. if(x->p==T_NIL)
    074. *T=y;
    075. else if (x == x->p->left)
    076. x->p->left = y;
    077. else
    078. x->p->right = y;
    079. y->left = x;
    080. x->p=y;
    081.  
    082. y->Max = x->Max;                         //添加语句维护Max
    083. x->Max = GetMax(x->left->Max,x->right->Max,x->INT.high);
    084. }
    085. void Right_Rotate(Node **T,Node * y)   //右旋
    086. {
    087. Node *x=y->left;
    088.  
    089. y->left =x->right;
    090. if (x->right != T_NIL)
    091. x->right->p=y;
    092. x->p=y->p;
    093. if(y->p==T_NIL)
    094. *T=x;
    095. else if (y == y->p->left)
    096. y->p->left = x;
    097. else 
    098. y->p->right = x;
    099. x->right = y;
    100. y->p=x;
    101.  
    102. x->Max = y->Max;                         //添加语句维护Max
    103. y->Max = GetMax(y->left->Max,y->right->Max,y->INT.high);
    104. }
    105. Node* Interval_Insert_Fixup(Node *T,Node *z)
    106. {
    107. Node * y=NULL;
    108. while( z->p->color == red)       //违反了性质4,迭代进行修正
    109. {
    110. if (z->p == z->p->p->left)
    111. {
    112. y = z->p->p->right;
    113. if ( y->color == red)    // case 1 叔结点为红色
    114. {
    115. z->p->color = black;    //父节点涂黑
    116. y->color = black;       //叔结点涂黑
    117. z->p->p->color = red;   //祖结点涂红
    118. z = z->p->p;            //向上迭代,更新z的位置
    119. }
    120. else if ( z == z->p->right) //case 2 叔结点为黑色且z为双亲的右孩子
    121. {
    122. z = z->p;
    123. Left_Rotate(&T,z);
    124. z->p->color = black;    //case2 已转为 case3 继续处理
    125. z->p->p->color = red;
    126. Right_Rotate(&T,z->p->p);// while循环终止
    127. }
    128. else                      // case 3 叔结点为黑色且z为双亲的左孩子
    129. {
    130. z->p->color = black;
    131. z->p->p->color = red;
    132. Right_Rotate(&T,z->p->p);//   while循环终止
    133. }
    134. }
    135.  
    136. else                      //对称处理
    137. {
    138.  
    139. y = z->p->p->left;
    140. if ( y->color == red)    // case 1 叔结点为红色
    141. {
    142. z->p->color = black;
    143. y->color = black;
    144. z->p->p->color = red;
    145. z = z->p->p;
    146. }
    147.  
    148. else if ( z == z->p->left) //case 2 叔结点为黑色且z为双亲的右孩子
    149. {
    150. z = z->p;
    151. Right_Rotate(&T,z);
    152. z->p->color = black;
    153. z->p->p->color = red;
    154. Left_Rotate(&T,z->p->p);//
    155. }
    156. else                      // case 3
    157. {
    158. z->p->color = black;
    159. z->p->p->color = red;
    160. Left_Rotate(&T,z->p->p);
    161. }
    162.  
    163.
    164. }
    165.  
    166. T->color = black;          //保证不会违反性质2,对根节点涂黑
    167. return T;
    168. }
    169. Node *Interval_Insert(Node *Root,Node * z)   //红黑树插入,返回树的根
    170. {
    171. Node * y=T_NIL;
    172. Node * x=Root;
    173. while( x != T_NIL)                 //找到结点z要插入的位置   
    174. {
    175. if ( z->Max > x->Max)     //比较新插入的结点z与结点x的Max大小;
    176. {
    177. x->Max = z->Max;
    178. }
    179. y=x;
    180. if (z->INT.low < x->INT.low)
    181. x = x->left;
    182. else
    183. x = x->right;
    184. }
    185. z->p = y;
    186. if ( y == T_NIL)    //插入第一个结点作为根节点的情况 
    187. Root = z;
    188. else if (z->INT.low < y->INT.low)
    189. y->left = z;
    190. else   
    191. y->right = z;
    192.  
    193. Root = Interval_Insert_Fixup(Root,z);    //插入完毕后,对红黑树的颜色进行修正
    194. return Root;
    195. }
    196. Node * Establish(int A[][2],int len)   //建立红黑树
    197. {
    198. Node * T,*node;
    199. int i=0;
    200. node=NULL;
    201. T_NIL=(Node *)malloc(sizeof(Node));  //建立T_NIL结点
    202. T_NIL->p=NULL;
    203. T_NIL->left=NULL;
    204. T_NIL->right=NULL;
    205. T_NIL->INT.low=-1;
    206. T_NIL->color=black;
    207. T_NIL->Max=0;
    208. T=T_NIL;
    209. for (i=0;i<len;i++)
    210. {
    211. node =(Node *)malloc(sizeof(Node));
    212. node->p =T_NIL;
    213. node->left=T_NIL;
    214. node->right=T_NIL;
    215. node->INT.low=A[i][0];         //以INT.low左作为关键字
    216. node->INT.high=A[i][1];        
    217. node->Max = A[i][1];          
    218. node->color=red;
    219. T=Interval_Insert(T,node);
    220. }
    221. return T;
    222. }
    223.  
    224. void RB_Transplant(Node **T,Node * u,Node * v)  //结点替代函数
    225. {
    226. if (u->p == T_NIL)
    227. *T = v;
    228. else if (u == u->p->left)
    229. u->p->left = v;
    230. else
    231. u->p->right = v;
    232. v->p = u->p;               //此处赋值无条件,v如果是T_NIL也要进行赋值
    233. }
    234. Node* Interval_Delete_Fixup(Node * T,Node * x)
    235. {
    236. Node *w=NULL;
    237. while( x != T && x->color == black)      //循环迭代处理
    238. {
    239. if ( x == x->p->left )
    240. {
    241. w = x->p->right;
    242. if (w->color == red)             // case 1 ------> case 2 , case 3 ,case 4
    243. {
    244. w->color = black;
    245. x->p->color =red;
    246. Left_Rotate(&T,x->p);
    247. w = x->p->right;
    248. }
    249. if ( w->left->color == black && w->right->color == black ) //case 2 ------>go on / stop
    250. {
    251. w->color = red;
    252. x = x->p;
    253. }
    254. else if ( w->right->color == black)   // case 3 ---->case 4---->stop
    255. {
    256. w->left->color = black;
    257. w->color =red ;
    258. Right_Rotate(&T,w);
    259.  
    260. w = x->p->right ;                   //转成case 4处理
    261. w->color = x->p->color;
    262. x->p->color = black;
    263. w->right->color = black;
    264. Left_Rotate(&T,x->p);
    265. x = T;
    266. }
    267. else                               // case 4 ------------------->stop
    268. {
    269. w->color = x->p->color;
    270. x->p->color = black;
    271. w->right->color = black;
    272. Left_Rotate(&T,x->p);
    273. x = T;
    274. }
    275. }
    276. else
    277. {
    278.  
    279. w = x->p->left;
    280.  
    281. if (w->color == red)                // case 1 ------> case 2 , case 3 ,case 4
    282. {
    283. w->color = black;
    284. x->p->color =red;
    285. Right_Rotate(&T,x->p);
    286. w = x->p->left;
    287. }
    288. if ( w->right->color == black && w->left->color == black ) //case 2 ------>go on/stop
    289. {
    290.  
    291. w->color = red;
    292. x = x->p;
    293. }
    294. else if ( w->left->color == black)      // case 3 -----> case 4----->stop
    295. {
    296. w->right->color = black;
    297. w->color =red ;
    298. Left_Rotate(&T,w);
    299.  
    300. w = x->p->left ;                    //转成case 4处理
    301. w->color = x->p->color;
    302. x->p->color = black;
    303. w->left->color = black;
    304. Right_Rotate(&T,x->p);
    305. x = T;
    306. }
    307. else                                  // case 4 -------------->stop
    308. {
    309. w->color = x->p->color;
    310. x->p->color = black;
    311. w->left->color = black;
    312. Right_Rotate(&T,x->p);
    313. x = T;
    314. }
    315. }
    316. }
    317.  
    318. x->color = black;                       //可能由case2退出,那把x涂黑即可,见分析!也可能有case4退出,把根节点涂黑
    319. return T;
    320. }
    321. Node * Interval_Delete(Node *T ,Node *z)
    322. {
    323.  
    324. Node * x =NULL;
    325. Node * y =z;
    326. Node * temp = y->p;
    327. enum colors y_original_color = y->color;   //记录下删除前z的颜色
    328. if ( z->left == T_NIL)                     //左子树不存在的情况 
    329. {  
    330. x = z->right;
    331. RB_Transplant(&T,z,z->right);
    332.  
    333.  
    334. }
    335. else if ( z->right == T_NIL)              //右子树不存在
    336. {
    337. x = z->left;
    338. RB_Transplant(&T,z,z->left);
    339.  
    340.  
    341. }
    342. else                                     //左右都存在的情况
    343. {
    344. y = Tree_Minimum(z->right);            //找到后继y
    345. temp = y->p;
    346. y_original_color = y->color;           //记录下y转移前的颜色
    347. x = y->right;
    348. if ( y->p == z)                       //如果y是z的子结点
    349. {
    350. x->p = y;
    351. }
    352. else
    353. {
    354. RB_Transplant(&T,y,y->right);    //如果y不是z的子结点,用y的右子树代替y的位置
    355. y->right = z->right;
    356. y->right->p = y;
    357. }
    358. RB_Transplant(&T,z,y);           //y替代z的位置 ,不论y是不是T_NIL  
    359. y->left = z->left;
    360. y->left->p = y;
    361. y->color = z->color;             //把y的颜色改成z的颜色  
    362. }
    363.  
    364. while( temp != T_NIL )             //从要删除的结点或其后继开始向上修复红黑树
    365. {      
    366. temp->Max = GetMax(temp->left->Max,temp->right->Max,temp->INT.high);
    367. temp = temp->p;    
    368. }
    369.  
    370.  
    371. if ( y_original_color == black)   //判断y的颜色,若为黑色,需要修复
    372. T=Interval_Delete_Fixup(T,x);
    373.  
    374. return T;
    375. }
    376.  
    377. Node * Tree_Search(Node *T ,int k)  //寻找数k是否在树中,且返回数k的地址
    378. {  
    379.  
    380. while(T != T_NIL && T->INT.low != k)
    381. {
    382. if ( k < T->INT.low)
    383. T=T->left;
    384. else
    385. T=T->right;
    386. }
    387.  
    388. if ( T == T_NIL)
    389. {    
    390. return NULL;
    391. }
    392.  
    393. else
    394. {
    395. return T;
    396. }
    397.  
    398. }
    399. Node * Interval_Search(Node *T ,struct Interval *i)  //寻找数k是否在树中,且返回数k的地址
    400. {  
    401. Node * x = T;
    402. while(x != T_NIL && ((x->INT.high < i->low)||(x->INT.low > i->high)))  //不重叠
    403. {
    404. if (x->left != T_NIL && x->left->Max >= i->low)  //在其左子树中搜索
    405. {
    406. x = x->left;
    407. }
    408. else
    409. {
    410. x = x->right;
    411. }
    412. }
    413.  
    414. return x;
    415. }
    416. void main()
    417. {
    418. int A[][2]={0,3,                   //区间
    419. 5,8,
    420. 6,10,
    421. 8,9,
    422. 15,23,
    423. 16,21,
    424. 17,19,
    425. 19,20,
    426. 25,30,
    427. 26,26};
    428.  
    429. int length = sizeof(A)/sizeof(A[0]); //数组区间的长度
    430. Node *T,*temp;
    431. struct Interval i;
    432. i.low = 22;
    433. i.high = 25;
    434.  
    435. T=Establish(A,length);        //建立红黑树,返回根节点T
    436. printf("中序遍历:\n");
    437. Inorder_Tree_Walk(T);printf("\n");   //中序遍历输出
    438. printf("-----------删除操作后-------------\n");  
    439. T=Interval_Delete(T,Tree_Search(T,6));
    440. printf("中序遍历:\n");
    441. Inorder_Tree_Walk(T);
    442. printf("\n");
    443.  
    444. temp = Interval_Search(T,&i);
    445. printf("____%d___%d__", temp->INT.low,temp->INT.high);
    446.  
    447. }</code>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值