Golang realization of the red-black tree

Source: Internet
Author: User
Tags truncated
This is a creation in Article, where the information may have evolved or changed.

Red-Black tree is a binary search tree based data structure, which has the following properties:

(1) The nature of the two-fork search tree It all has

(2) Each node has a color attribute, each node is either red or black.

< strong> (3)   root node must be black

(4)   each leaf node (nil node) is black

(5)   If a node is red, then its two children are black

(6) the number of black nodes is the same on each node's path to its descendants ' leaf nodes


Compared to binary search tree, red black tree In addition or deletion of elements at the same time need to adjust the depth of the tree, so need to use the tree structure of some rotation operations, the following example code is very detailed, you can see Leftrotate () and rightrotate () function of how to achieve rotation. If someone finds a bug, please post it in the message ~



This code is in the previous "Golang in OO way to achieve two binary search tree" in the code processing implementation, because I do not have the technology in place ... Out of several bugs, tinkering, write a lot of code, everyone make a look ... :

Package Mainimport ("FMT") var count inttype TreeNode struct {data Float64color string//than binary find tree to have one more color attribute lchild *treenode Rchild *treenodeparent *treenode}type rbtree struct {root *treenodecur *treenodecreate *treenode}func (RBT *RBTree) A DD (data float64) {rbt.create = new (TreeNode) Rbt.create.data = Datarbt.create.color = "Red" if!rbt. IsEmpty () {rbt.cur = rbt.rootfor {if data < Rbt.cur.data {//If the value to be inserted is smaller than the value of the current node, the current node points to the left child of the current node, if//left child is empty, Just insert the new value on the left child if Rbt.cur.lchild = = Nil {rbt.cur.lchild = Rbt.createrbt.create.parent = Rbt.curbreak} else {rbt.cur = Rbt.cur . Lchild}} else if data > rbt.cur.data {//If the value you want to insert is larger than the value of the current node, the current node points to the right child of the current node, if//right child is empty, insert a new value on the right child if rbt.cur.rchild = = Nil {rbt.cur.rchild = Rbt.createrbt.create.parent = Rbt.curbreak} else {rbt.cur = Rbt.cur.rchild}} else {//If the value to be inserted already exists in the tree , Exit Return}}} else {rbt.root = Rbt.createrbt.root.color = "Black" rbt.root.parent = nilreturn}// Fixed red-black properties after inserting a node rbt.insertbalancefixup (rbt.create)}func (RBT *rbtree) Delete (data float64) {var (dEletenode func (node *treenode) node *treenode = RBT. Search (data) parent *treenoderevise string) if node = = Nil {return} else {parent = node.parent}//below this small piece of code is used to determine the position of the alternate truncated point  The node is which descendant if Node.lchild = Nil && Node.rchild = = Nil {revise = "none"} else if parent = nil {revise = "root"} else if node = = Parent.lchild {revise = "left"} else if node = = parent.rchild {revise = ' right '}deletenode = func (node *treeno DE) {if node = = Nil {return}if Node.lchild = nil && Node.rchild = nil {///If the node to be deleted has no children, simply delete it (without worrying about ~.~!) if node = = Rbt.root {rbt.root = nil} else {if Node.parent.lchild = = Node {node.parent.lchild = nil} else {Node.parent.rchi  ld = nil}}} else if node.lchild! = Nil && Node.rchild = = Nil {//If the node to be deleted is only left child or right child, let the node's parent node point to its pointer to its//child can if node = = Rbt.root {node.lchild.parent = Nilrbt.root = Node.lchild} else {node.lchild.parent = Node.parentif node.parent.lchild = = Node {node.parent.lchild = Node.lchild} else {node.parent.rchild = node.lchild}}} else if node. lchild = = Nil && Node.rchild! = Nil {if node = = rbt.root {node.rchild.parent = Nilrbt.root = Node.rchild} else {n Ode.rchild.parent = node.parentif Node.parent.lchild = = Node {node.parent.lchild = Node.rchild} else {Node.parent.rchild = Node.rchild}}} else {//If the node to be deleted has both a left child and a right child, assign the node's direct successor value to the section//point, and then delete the immediate successor node to successor: = RBT. Getsuccessor (node.data) node.data = Successor.datanode.color = Successor.colordeletenode (successor)}}deletenode ( node) If Node.color = = "Black" {if revise = = "Root" {Rbt.deletebalancefixup (Rbt.root)} else if revise = = "Left" {Rbt.delete Balancefixup (Parent.lchild)} else if revise = = "Right" {rbt.deletebalancefixup (Parent.rchild)}}//as to why removing the red node without adjusting the balance , the black "Introduction to Algorithmic (Second edition)" explains this://When the red node is deleted//(1) The black height of the nodes in the tree has not changed//(2) There is no two adjacent red nodes//(3) If the deleted node is red, it cannot be the root, so the root is still black}// This function is used to fix the red Black Nature func (RBT *rbtree) insertbalancefixup (Insertnode *treenode) {var uncle *treenodefor) After the red-black tree performs an insert operation Insertnode.color = = "Red" && insertnode.parent.color = = "Red" {//Get the Uncle node of the newly inserted node (another section with the same root as the parent nodePoint) if insertnode.parent = = insertnode.parent.parent.lchild {Uncle = Insertnode.parent.parent.rchild} else {uncle = Insertnode.parent.parent.lchild}if Uncle! = Nil && Uncle.color = = "Red" {//If the Uncle node is red, just as shown in the change (--black,0-> red)                        ://|    |//1 10<-new node ptr come here///\--------\/\//2003--------/ 2 3//////40<-new node ptr 40////This situation can be looped all the time, knowing that the new node PTR refers to root when it exits (the root color is still black) Uncle.color, Insertnode.parent.color = "Black", "black" Insertnode = insertnode.parent.parentif Insertnode = Rbt.root | |                        Insertnode = = Nil {Return}insertnode.color = "red"} else {//If Uncle node is empty or Uncle node is black, change as shown://|                              |//1 <-right rotate 2//\--------\/\//3--------/4001/// \//40<-new node ptr 3////Of course, this is only a case when the Uncle node is black, if the node 4 is a 2-node right child, then//can first rotate to the left at the 2 node, which translates into The situation.In the other two cases, I think I understand if insertnode.parent = = Insertnode.parent.parent.lchild {if Insertnode = = Insertnode.parent.rchild { Insertnode = Insertnode.parentrbt.LeftRotate (insertnode)}insertnode = Insertnode.parentinsertnode.color = "BLACK" Insertnode = Insertnode.parentinsertnode.color = "Red" RBT. Rightrotate (Insertnode)} else {if Insertnode = = Insertnode.parent.lchild {Insertnode = Insertnode.parentrbt.RightRotate (insertnode)}insertnode = Insertnode.parentinsertnode.color = "Black" Insertnode = Insertnode.parentinsertnode.color = "Red" RBT. Leftrotate (insertnode)}return}}}//This function is used to fix the red-black nature func (RBT *rbtree) deletebalancefixup (node *treenode) after the red-black tree performs a delete operation { var brother *treenodefor Node! = Rbt.root && Node.color = = "BLACK" {//Red black fix on Delete requires consideration of four cases (the "X" below refers to a new node that replaces the location of the truncated point)//(1                              The brother node of x is red://| |//1 3//\--------\/\//x-> 2 <-brother----- ---/10 5///\/\//4 5 x-> 2 4////(2) X's sibling node is black, and two children of the sibling node are black://| |//10x-> 10///\--------\/\//x-> 2 3 <-brother --------/2 03///\/\//4 5 4 5////(3) X                              Brother node is black, brother's left child is red, right child is black://| |//1010///\--------\/\//x-> 2 3 <-brother-----                                            ---/x->2 4///\ \//-503//        \//5////(4) X's sibling node is black, and the brother's right child is red://                              | |//1030x->root and loop while end///\--------\/\//X 2 3 <-brother--------/1  5///\/\//4005 2 04////above is the case of the Brother node at the right of X, on the left side of X is the opposite can be!if Node.parent.lchild = = Node && node.parent.rchild! = Nil {brother = node.parent.rchildif Brother.color = = "Red" {BR Other.color = "BLACK" Node.parent.color = "Red" RBT. Leftrotate (node.parent)} else if Brother.color = = "BLACK" && brother.lchild! = Nil && Brother.lchild.colo r = = "BLACK" && brother.rchild! = Nil && Brother.rchild.color = = "Black" {brother.color = "red" node = node . Parent} else if Brother.color = = "BLACK" && brother.lchild! = Nil && Brother.lchild.color = = "Red" && Amp Brother.rchild! = Nil && Brother.rchild.color = = "Black" {brother.color = "red" Brother.lchild.color = "Black" RBT.  Rightrotate (brother)} else if Brother.color = = "BLACK" && brother.rchild! = Nil && Brother.rchild.color = = "Red" {Brother.color = "red" Brother.rchild.color = "BLACK" Brother.parent.color = "Black" RBT.Leftrotate (brother.parent) node = rbt.root}} else if Node.parent.rchild = = Node && node.parent.lchild! = nil {broth ER = node.parent.lchildif Brother.color = = "Red" {Brother.color = "black" Node.parent.color = "Red" RBT. Rightrotate (node.parent)} else if Brother.color = = "BLACK" && brother.lchild! = Nil && Brother.lchild.col or = = "BLACK" && brother.rchild! = Nil && Brother.rchild.color = = "Black" {brother.color = "red" node = nod E.parent} else if brother.color = = "BLACK" && brother.lchild! = Nil && Brother.lchild.color = "BLACK" &am p;& brother.rchild! = Nil && Brother.rchild.color = = "Red" {Brother.color = "red" Brother.rchild.color = "Black "RBT. Leftrotate (brother)} else if Brother.color = = "BLACK" && brother.lchild! = Nil && Brother.lchild.color = = "Red" {Brother.color = "red" Brother.lchild.color = "BLACK" Brother.parent.color = "Black" RBT. Rightrotate (brother.parent) node = rbt.root}} else {Return}}}func (RBTRbtree) Getroot () *treenode {if rbt.root! = Nil {return Rbt.root}return nil}func (RBT rbtree) IsEmpty () bool {if rbt.root = = Nil {return True}return false}func (RBT rbtree) Inordertravel () {var inordertravel func (node *treenode) Inordertravel = Func (node *treenode) {if node! = Nil {inordertravel (node.lchild) fmt. Printf ("%g", Node.data) Inordertravel (node.rchild)}}inordertravel (rbt.root)}func (RBT rbtree) Search (data float64) * TreeNode {//and add operation is similar, as long as the number is smaller than the current node to go to the left child, than the current node big on the right child to turn the idea//all the way down, know find the value to find return can rbt.cur = rbt.rootfor {if rbt.cur = nil { Return NIL}IF Data < Rbt.cur.data {rbt.cur = rbt.cur.lchild} else if data > rbt.cur.data {rbt.cur = rbt.cur.rchild} else {return Rbt.cur}}}func (RBT rbtree) getdeepth () int {var getdeepth func (node *treenode) intgetdeepth = func (node *tre Enode) int {if node = = Nil {return 0}if Node.lchild = nil && Node.rchild = nil {return 1}var (ldeepth int = getd Eepth (node.lchild) rdeepth int = getdeepth (node.rchild)) if ldeepth > rdeepth {return lDeepth + 1} else {return rdeepth + 1}}return getdeepth (rbt.root)}func (RBT rbtree) getmin () float64 {//depending on the nature of the binary lookup tree, the leftmost node in the tree is the node with the smallest value if Rbt.root = = Nil {Return-1}rbt.cur = rbt.rootfor {if rbt.cur.lchild! = Nil {rbt.cur = Rbt.cur.lchild} else {RET  Urn Rbt.cur.data}}}func (RBT rbtree) Getmax () float64 {//depending on the nature of the binary lookup tree, the rightmost node in the tree is the node with the largest value if Rbt.root = nil {return-1}rbt.cur = rbt.rootfor {if rbt.cur.rchild! = Nil {rbt.cur = Rbt.cur.rchild} else {return Rbt.cur.data}}}func (RBT rbtree) Getprede Cessor (data float64) *treenode {getmax: = func (node *treenode) *treenode {if node = = Nil {return nil}for {if node.rchild! = Nil {node = Node.rchild} else {return Node}}}node: = RBT. Search (data) if node! = Nil {if node.lchild! = Nil {//If this node has a left child, then its direct precursor is the rightmost node of its left subtree, because the nodes that are smaller than this//node value are in the left subtree, The most significant of these nodes is the rightmost node, return Getmax (Node.lchild)} else {///If the node has no left child, then follow its parent node and know that the parent node of the parent node is the parent node. Then the parent node of the parent node is the direct precursor for {if node = = Nil | | node.parent = NIL {break}if node = = Node.parent.rchild {return Node.parent}node= Node.parent}}}return Nil}func (rbt rbtree) getsuccessor (data float64) *treenode {getmin: = func (node *treenode) *treenod  e {if node = = Nil {return nil}for {if node.lchild! = Nil {node = Node.lchild} else {return node}}}//reference a function looking for a direct precursor to see node: = Rbt.  Search (data) If node = nil {if node.rchild! = Nil {return getmin (Node.rchild)} else {for {if node = Nil | | node.parent = = Nil {break}if node = = Node.parent.lchild {return node.parent}node = Node.parent}}}return Nil}func (rbt *rbtree) Clear () {                               Rbt.root = Nilrbt.cur = Nilrbt.create = nil}/** * Rotation plot (with left rotation as an example): * | |   *0<-left rotate * \----------\/\ *----------                               R */\ \ * L R L * * * * | |   *0<-left rotate * \----------\/\ *----------              * \             \ * Nil <-don ' t forget it should be nil */func (RBT *rbtree) leftrotate (Node *treenode) {if Node.rchild = = Nil {return}right_child: = node.rchild//The left child of the right child of the node that will be rotated is assigned to the right child of this node, it is best to write in the order of the following 3 lines of code,// Otherwise the right child's left child of the node is nil, it is easy to forget to put the right child of this node also set to Nil.node.rchild = Right_child.lchildif Node.rchild! = Nil {node.rchild.parent = node}//The parent node of the right child of the node that you want to rotate points to the parent node of the current node. If the parent node is the root node to be specially handled right_child.parent = node.parentif Node.parent = = Nil {rbt.root = Right_child} else {if Node.parent.lchild = = Node {node.parent.lchild = Right_child} else {node.parent.rchild = right_child}}//the preparation work is complete, you can start to rotate, Let the left child of the right child of the node that you want to rotate point to that node,//Do not forget to point the parent node pointer of this rotated node to the new parent node Right_child.lchild = Nodenode.parent = Right_child}func (RBT *rbtree The process of Rightrotate (node *treenode) {//Right rotation is exactly the opposite of leftrotate () if Node.lchild = = Nil {return}left_child: = Node.lchildnode.lchild = left_child.rchildif Node.lchild! = Nil {node.lchild.parent = Node}left_child.parent = Node.parentif Node.parent = = Nil {rbt.root = Left_chilD} else {if Node.parent.lchild = = Node {node.parent.lchild = Left_child} else {node.parent.rchild = Left_child}}left_child . rchild = Nodenode.parent = Left_child}func Main () {var rbt rbtreerbt.add (9) RBT. ADD (8) RBT. ADD (7) RBT. ADD (6) RBT. ADD (5) RBT. ADD (4) RBT. ADD (3) RBT. ADD (2) RBT. ADD (1) fmt. Println (RBT. Getdeepth ())}



The results of the operation are as follows:


If it is a two-fork search tree, then the depth of the tree will be 9, so it is no different from the normal linear structure, it can be seen that the red and black tree is indeed a better two-fork search tree.



If reproduced please specify the source: http://blog.csdn.net/gophers/article/details/23608025





Related Article

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.