The difference between the two nearest numbers in a dynamic set

Source: Internet
Author: User

Question:

Thoughts:

Since it is a dynamic set, we need to use a linked list to store data for easy insertion and deletion. Therefore, we can use the binary linked list, that is, the red and black trees, to store data. Because the red and black trees are balanced, we can get a better query time. However, we can not simply use the red and black trees. Because the basic red and black trees do not have the min_gap operation, we need to modify and maintain the original red and black trees by ourselves.

How can I add min_gap TO THE RED/black tree? We need to add the max and Min pointer to the red/black tree structure first. For this operation, you can find the maximum and minimum values for the worst time of O (1). Of course, you only need to add some new code. Now that the new pointer has been added, we use the original red/Black Tree insertion and deletion operation as a subroutine to add a new insertion and deletion operation for this question. The new insertion and deletion function maintains two trees, one composed of the Set Q, and the other composed of the difference of each of the two closest numbers of Q.

How can I add a new insert/delete operation? Perform the following steps:

Insert operation: ① Insert the new node Z into the tree.

② Locate the forward X1 and the next X2 of the new node Z.

③ Locate the gap between the new node and the frontend and the successor respectively, and insert them into the two tree T2.

④ Delete the gap between X1 and X2.

Delete operation: ① find the node X with the value of Z.

② Locate the forward X1 and the next X2 of the node Z to be deleted.

③ Locate the gap between the node to be deleted and the frontend and the successor, and delete the node respectively.

④ Before Z is deleted, a new gap will be formed after Z is deleted, and the gap will be inserted.

⑤ Delete Z.

The Code is as follows:

# Include <iostream> # include <time. h> using namespace STD; # define black 0 # define Red 1 # define nil-1 # define Len sizeof (struct tree) # define N 10 // here change the data volume struct tree {struct tree * left; struct tree * right; struct tree * parent; int key; int color; struct tree * min; // record the smallest keyword struct tree * max in the tree with X as the root node; // record the largest keyword in the tree with X as the root node}; struct tree * root1 = NULL; struct tree * root2 = NULL; struct tree * nil = NULL; // the minimum value of the Binary Search Tree in non-recursive versions Struct tree * iterative_tree_minimum (struct tree * X) {While (X! = Nil & X-> left! = Nil) {x = x-> left;} return X;} // the maximum value of the Binary Search Tree in non-recursive versions, struct tree * iterative_tree_maximum (struct tree * X) {While (X! = Nil & X-> right! = Nil) {x = x-> right;} return X;} void left_rotate (struct tree * & root, struct tree * X) {// left rotation: in three steps, ① ② describes the rotation code. Struct tree * Y = x-> right; // set the y node. If (Y-> left! = Nil) x-> max = Y-> left-> MAX; // else X-> max = x for additional information maintenance; y-> min = x-> min; X-> right = Y-> left; // The line of code and the IF structure below express "y's left child becomes the right child of X ". ① If (Y-> left! = Nil) {Y-> left-> parent = x;} y-> parent = x-> parent; // The line of code and the following if-else structure expression process is "Y becomes the new root of the subtree ". ② If (X-> parent = nil) {root = y;} else if (x = x-> parent-> left) {X-> parent-> left = y;} else X-> parent-> right = y; y-> left = X; // This line of code and the following line both express "X is the left child of Y ". ③ X-> parent = y;} void right_rotate (struct tree * & root, struct tree * X) {// right rotation: in three steps, ① ② describes the rotation code. Struct tree * Y = x-> left; // set the y node. If (Y-> right! = Nil) x-> min = Y-> right-> min; // else X-> min = x for additional information maintenance; y-> max = x-> MAX; X-> left = Y-> right; // The line of code and the IF structure below express "y's left child becomes the right child of X ". ① If (Y-> right! = Nil) {Y-> right-> parent = x;} y-> parent = x-> parent; // The line of code and the following if-else structure expression process is "Y becomes the new root of the subtree ". ② If (X-> parent = nil) {root = y;} else if (x = x-> parent-> right) {X-> parent-> right = y;} else X-> parent-> left = y; y-> right = X; // This line of code and the following line both express "X is the left child of Y ". ③ X-> parent = y;} void rb_insert_fixup (struct tree * & root, struct tree * z) {While (Z-> parent-> color = red) {If (Z-> parent = z-> parent-> left) {struct tree * Y = z-> parent-> right; // uncle node if (Y-> color = red) // Case 1: The uncle node is red {// color P1, y, and P2 to maintain the property of 5. And solved the problem that the parent node of Z and Z are both red nodes Z-> parent-> color = black; y-> color = black; z-> parent-> color = Red; Z = z-> parent; // take z's grandfather node as the new node Z into the next loop} else {If (Z = z-> parent-> right) // Scenario 2: check whether Z is a right child and the primary node is black, provided that the P1 node is not a leaf node {// use a left-hand node to convert case 2 to case 3 Z = z-> parent; left_rotate (root, Z); // after entering the if statement, we can see that the rotation node cannot be a leaf node, so we don't have to judge whether Z is a leaf node.} Z-> parent-> color = black; // Case 3: Z is a left child and the uncle node is black, change the color of the parent and grandfather node of Z and perform a right-hand operation to keep the properties 5 Z-> parent-> color = Red; right_rotate (root, z-> parent); // Since P2 may be a leaf node, it is best to use an if judgment} The else branch below is similar to the above, note that the rotation in Case 2 and Case 3 of the else branch is exactly the inverse of the IF branch. {Struct tree * Y = z-> parent-> left; If (Y-> color = red) {z-> parent-> color = black; y-> color = black; Z-> parent-> color = Red; Z = z-> parent ;} else {If (Z = z-> parent-> left) {z = z-> parent; right_rotate (root, Z );} z-> parent-> color = black; Z-> parent-> color = Red; left_rotate (root, Z-> parent );}}} root-> color = black; // Finally, the root point is black .} Void rb_insert (struct tree * & root, struct tree * z) {struct tree * Y = nil; struct tree * x = root; while (X! = Nil) {Y = x; If (Z-> key <X-> key) {x = x-> left;} else x = x-> right ;} z-> parent = y; If (y = nil) {root = z;} else if (Z-> key <Y-> key) {Y-> left = z; while (y) {Y-> min = z; if (Y-> parent = nil | Y-> parent-> right = y) {break;} y = Y-> parent ;}} else {Y-> right = z; while (y) {Y-> max = z; if (Y-> parent = nil | Y-> parent-> left = y) {break;} y = Y-> parent ;}} z-> left = nil; // assign a null value to the left and right children of the insert node. Z-> right = nil; Z-> color = Red; // The insert node is red. Z-> max = z-> min = z; rb_insert_fixup (root, Z);} void rb_transplant (struct tree * & root, struct tree * u, struct tree * V) {If (u-> parent = nil) root = V; else if (u = u-> parent-> left) U-> parent-> left = V; else U-> parent-> right = V; V-> parent = u-> parent;} // find the precursor struct tree * tree_predecessor (struct tree * X) of the Binary Search Tree) {If (X-> left! = Nil) {return iterative_tree_maximum (X-> left);} struct tree * Y = x-> parent; while (y! = Nil & X = Y-> left) {x = y; y = Y-> parent;} return y ;} // find the next struct tree * tree_successor (struct tree * X) of the Binary Search Tree {If (X-> right! = Nil) {return iterative_tree_minimum (X-> right);} struct tree * Y = x-> parent; while (y! = Nil & X = Y-> right) {x = y; y = Y-> parent;} return y ;} // non-recursive Binary Search Tree lookup function struct tree * iterative_tree_search (struct tree * X, int K) {While (X! = Nil & K! = X-> key) {If (k <X-> key) {x = x-> left;} else x = x-> right;} return X ;} void rb_delete_fixup (struct tree * & root, struct tree * X) {struct tree * w = NULL; // W is the sibling node of X while (X! = Root & X-> color = black) // If X is black and is not the root node, the loop is executed. {// X is a node with dual colors. The purpose of adjustment is to move the black attribute of X up. If (x = x-> parent-> left) {W = x-> parent-> right; if (W-> color = red) // scenario 1: x's sibling node W is red. {// Change the color of W and X. P + one rotation to Case 2, 3, and 4. W-> color = black; X-> parent-> color = Red; left_rotate (root, X-> parent); W = x-> parent-> right ;} if (W-> left-> color = Black & W-> right-> color = black) // Case 2: X's sibling node W is black, in addition, both child nodes of W are black. {W-> color = Red; // remove a heavy black from X and W. X is black, and W is red. X = x-> parent; // The x node moves up to become the new node to be adjusted.} Else {If (W-> right-> color = black) // Case 3: The sibling node W of X is black, and the left child of W is red, w's right child is black. {// Switch the color + rotation of W and W. Left to case 4. W-> left-> color = black; W-> color = Red; right_rotate (root, W); W = x-> parent-> right ;} w-> color = x-> parent-> color; // The following is the case 4: The sibling node W of X is black, and the right child of W is red. X-> parent-> color = black; // set X. P and W. Right to black + rotate to remove the extra black of X. W-> right-> color = black; left_rotate (root, X-> parent); X = root; // X becomes the root node and ends the loop.} The following else // is similar to the IF branch above. {W = x-> parent-> left; If (W-> color = red) {w-> color = black; X-> parent-> color = Red; right_rotate (root, X-> parent); W = x-> parent-> left ;} if (W-> left-> color = Black & W-> right-> color = black) {w-> color = Red; X = x-> parent;} else {If (W-> left-> color = black) {w-> right-> color = black; w-> color = Red; left_rotate (root, W); W = x-> parent-> left;} w-> color = x-> parent-> color; x-> parent-> color = black; W-> left-> color = black; Right_rotate (root, X-> parent); X = root ;}}x-> color = black;} void rb_delete (struct tree * & root, struct tree * z) {struct tree * Y = z, * X; // y indicates the node to be deleted or moved. Int y_original_color = Y-> color; // Save the original color of Y, prepare for the final adjustment. Struct tree * k = z-> parent, * P = z-> parent, * t = z-> parent; If (Z-> left = nil) {x = z-> right; // X points to the unique subnode or leaf node of Y, save the trace of x and move it to the original position of Y. If (Z-> parent-> left = z) {If (X! = Nil) {While (P! = Nil & P-> parent-> left = P) {P-> min = x-> min; P = p-> parent ;} p-> min = x-> min;} else {While (P! = Nil & P-> parent-> left = P) {P-> min = K; P = p-> parent;} p-> min = K ;}} else {If (X! = Nil) {While (P! = Nil & P-> parent-> right = P) {P-> max = x-> MAX; P = p-> parent ;} p-> max = x-> MAX;} else {While (P! = Nil & P-> parent-> right = P) {P-> max = K; P = p-> parent;} p-> max = K ;}} rb_transplant (root, Z, Z-> right); // use Z. replace the subtree with Z as the root of right .} Else if (Z-> right = nil) {x = z-> left; // X points to the unique subnode or leaf node of Y, save the trace of x and move it to the original position of Y. If (Z-> parent-> right = z) {While (P! = Nil & P-> parent-> right = P) {P-> max = x-> MAX; P = p-> parent ;} p-> max = x-> MAX;} else {While (P! = Nil & P-> parent-> left = P) {P-> min = x-> min; P = p-> parent ;} p-> min = x-> min;} rb_transplant (root, Z, Z-> left. replace left with the child tree with Z as the root .} Else {Y = iterative_tree_minimum (Z-> right); // find the successor of Z. Right. Y_original_color = Y-> color; // The new original node of Y is reset. X = Y-> right; // X points to the unique subnode or leaf node of Y, save the trace of x and move it to the original position of Y. Y-> min = z-> left-> min; If (Y-> parent = z) {X-> parent = y; // The parent node of Z cannot point to it because it is the node to be deleted, then point to y} else {struct tree * w = z-> right; if (Y-> right! = Nil) {While (W-> left! = Nil) {w-> min = x-> min; W = W-> left;} else {While (W-> left! = Nil) {w-> min = Y-> parent; W = W-> left;} y-> max = z-> MAX; // + rb_transplant (root, y, Y-> right); // use y. replace the subtree with Y as the root of right. Y-> right = z-> right; y-> right-> parent = y;} rb_transplant (root, Z, y ); // Replace the subtree rooted in Y with the subtree rooted in Z. Y-> left = z-> left; y-> left-> parent = y; y-> color = z-> color; // assign the color of the deleted node to Y to ensure that the color of the tree structure above y remains the same .} If (y_original_color = black) // The original color of Y is black, indicating that you need to adjust the red and black colors. Rb_delete_fixup (root, x); If (root = nil) {root-> max = root-> min = nil ;}} // traverse void inodertraverse (struct tree * P) {If (P! = Nil) {inodertraverse (p-> left); cout <p-> key <""; inodertraverse (p-> right );}} // We use various operations on the original red/black tree as subfunctions to create a new insertion/deletion function // The new insertion/deletion function maintains two trees, one of which is a tree composed of Q, there is also a void insert_gap (struct tree * & R1, struct tree * & R2, struct tree * z), which is composed of the difference between the two nearest numbers of Q) {// o (lgn) rb_insert (R1, Z); // Insert the new node into the tree first. Struct tree * X1 = tree_predecessor (z); // find X1 as the precursor struct tree * X2 = tree_successor (z); // find X2 as the successor if (x1! = Nil) {struct tree * x = new struct tree [Len]; X-> key = z-> key-x1-> key; rb_insert (R2, X ); // Insert the gap between Z and Z.} If (X2! = Nil) {struct tree * x = new struct tree [Len]; X-> key = x2-> key-z-> key; rb_insert (R2, X ); // insert Z's successor and Z's gap} If (x1! = Nil & X2! = Nil) {struct tree * x = iterative_tree_search (R2, x2-> key-x1-> key); If (X! = Nil) rb_delete (R2, x); // Delete the gap between the original X1 and X2} void delete_gap (struct tree * & R1, struct tree * & R2, int Z) {struct tree * x = iterative_tree_search (R1, Z); // query the node x struct tree * X1 = tree_predecessor (x) with the value of Z ); // The precursor struct tree * X2 = tree_successor (x) Where X1 is X; // The successor if (x1! = Nil) {struct tree * Y1 = iterative_tree_search (R2, z-x1-> key); rb_delete (R2, Y1 ); // locate the gap between Z and delete it} If (X2! = Nil) {struct tree * y2 = iterative_tree_search (R2, x2-> key-z); rb_delete (R2, Y2 ); // locate the subsequent gap between Z and delete it} If (x1! = Nil & X2! = Nil) {struct tree * D = new struct tree [Len]; D-> key = x2-> key-x1-> key; rb_insert (R2, d ); // after Z is deleted, the frontend and successor of Z will form a new gap to insert it} rb_delete (R1, x); // Delete Z at last .} Struct tree * min_gap (struct tree * R2) {return R2-> min;} void main () {srand (unsigned) Time (null )); int array1 [N] = {0}; For (Int J = 0; j <n; j ++) {array1 [J] = rand () % 100 + 1 ;} nil = new struct tree [Len]; nil-> key = nil; nil-> color = black; root2 = root1 = nil; int I = 0; struct tree * root = new struct tree [Len]; root-> key = array1 [I ++]; insert_gap (root1, root2, root); root1 = root; while (I! = N) {struct tree * z = new struct tree [Len]; Z-> key = array1 [I]; insert_gap (root1, root2, Z); I ++ ;} inodertraverse (root1); cout <Endl; inodertraverse (root2); cout <Endl; cout <"after insertion, Gap =" <min_gap (root2) -> key <Endl; cout <Endl; for (I = 0; I <n; I ++) {delete_gap (root1, root2, array1 [I]); after cout <"delete" <array1 [I] <", the dynamic set Q: Gap =" <min_gap (root2)-> key <Endl; inodertraverse (root1); cout <Endl; cout <"A collection composed of dynamic sets of Q, and each of the two gaps closest to data is:" <Endl; inodertraverse (root2); cout <Endl ;}}

Summary: In general, the running time of min_gap is O (1), while that of insert and delete is O (lgn ), note that the newly added insert/delete operation only involves the five operations that follow the forward direction of the original red/black tree insert/delete query. Each operation is O (lgn ), therefore, the new insert/delete operation time is O (lgn ). it does not affect the performance of the red/black tree. Besides, the newly added maximum and small pointers do not affect the operations in the original red and black trees. For example, the rotation only increases the constant time, while the insertion and deletion only adds the O (lgn) from the root to the leaf) path update operation, so it does not affect the performance. It may slightly affect the Constant Coefficient in O (lgn. Finally, because we need to maintain two shards, the storage space is increased. However, with the addition of tree T2, we can easily traverse all the gaps of the original data, it is not just the minimum gap.



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.