Golang program to implement a red-black tree


Red-Black Trees are binary search trees with consistent structure and height balance, capable of self-balancing. They are beneficial in efficient insertion, deletion, and search operations. In this article, we will take an in-depth look at how to implement a red-black tree in golanguage,in the first example we are directly going to build the tree, while in the second example we are going to build the tree using structure.

Explanation

A red black tree is a self-balancing binary search tree that during insertion and deletion operations, ensures balance by making sure each node within the binary search tree is designated a color - either red or black. This unique characteristic culminates in the tree following five crucial properties.

  • Either black or red is the color of every single node.

  • Black is the color of the root node.

  • Black is the color of every leaf, specifically the NIL node.

  • Black children are a requirement for any red node.

  • The number of black nodes found in any path from a particular node to its descendant leaves should remain constant.

Syntax

func (t *RedBlackTree) insert(root, node *Node) *Node

The syntax defines a function named insert written to preserve the Red-Black Tree when it adds a new node. For this, it requires both the root node and the node to be inserted as inputs.

Algorithm

  • Create a binary search tree as regular to start with.

  • Nodes that are new and have just been inserted are coloured red.

  • To keep the Red-Black Tree's five properties intact, we make sure to perform rotations and recoloring whenever necessary.

  • No red nodes should be consecutive following an insertion or rotation.

  • We need to apply rotations and recoloring as needed in the event of a violation in order to restore the properties.

Example 1

In this example, we directly going to implement a red-black tree in golanguage by defining a struct, through color-coding, and declaring parent-child relations among the nodes. We need to enclose the created root node within the RedBlackTree struct. Node insertion is achieved through the recursive insert method, which furthermore implements parent pointer adjustments. With the inOrder method, node data and color are viewed through performing an in-order traversal. The main function highlights a Red-Black Tree instance to finally yield the respective in-order traversal result.

package main
import "fmt"
type Color int
const (
   Red   Color = 0
   Black Color = 1
)
type Node struct {
   data   int
   color  Color
   parent *Node
   left   *Node
   right  *Node
}
type RedBlackTree struct{ root *Node }
func NewRedBlackTree() *RedBlackTree { return &RedBlackTree{} }
func (t *RedBlackTree) insert(root, node *Node) *Node {
   if root == nil {
      return node
   }
   if node.data < root.data {
      root.left = t.insert(root.left, node)
      root.left.parent = root
   } else if node.data > root.data {
      root.right = t.insert(root.right, node)
      root.right.parent = root
    }
   return root
}
func (t *RedBlackTree) inOrder(node *Node) {
   if node == nil {
      return
   }
   t.inOrder(node.left)
   fmt.Printf("%d (%s) ", node.data, func(c Color) string {
      if c == Red {
         return "R"
      }
      return "B"
   }(node.color))
   t.inOrder(node.right)
}
func main() {
   tree := NewRedBlackTree()
   data := []int{10, 20, 30, 15, 5}
   for _, d := range data {
      tree.root = tree.insert(tree.root, &Node{data: d, color: Red})
      fmt.Printf("Inserted: %d\n", d)
   }
   fmt.Println("\nIn-order Traversal:")
   tree.inOrder(tree.root)
}

Output

Inserted: 10
Inserted: 20
Inserted: 30
Inserted: 15
Inserted: 5

In-order Traversal:
5 (R) 10 (R) 15 (R) 20 (R) 30 (R)

Example 2

In this example, we indirectly going to implement a red-black tree in golanguage using a structure called `Node` to represent the elements incorporating color attributes. We define the `newNode­` function to create the Nodes which are then recursively added to the tree through the `insert` function, carefully considering their color values and establishing parent-child relationships along the way. For traversal purposes, there is an `inOrde­rTraversal` function that performs a left-root-right traversal of the tree. This function displays both node data and colors. The `main` function initializes a tree and inserts specific data points and finally the respctive in-order traversal.

package main
import "fmt"
type Color int
const (
   Red   Color = 0
   Black Color = 1
)
type Node struct {
   data   int
   color  Color
   parent *Node
   left   *Node
   right  *Node
}
func newNode(data int, color Color, parent, left, right *Node) *Node {
        	return &Node{data: data, color: color, parent: parent, left: left, right: right}
}
func insert(root *Node, data int) *Node {
   if root == nil {
      return newNode(data, Red, nil, nil, nil)
   }
   if data < root.data {
      root.left = insert(root.left, data)
      root.left.parent = root
   } else if data > root.data {
       root.right = insert(root.right, data)
       root.right.parent = root
     }
   return root
}
func inOrderTraversal(root *Node) {
   if root == nil {
      return
   }
   inOrderTraversal(root.left)
   fmt.Printf("%d (%s) ", root.data, colorToString(root.color))
   inOrderTraversal(root.right)
}
func colorToString(color Color) string {
   if color == Red {
      return "R"
   }
   return "B"
}
func main() {
   var root *Node
   data := []int{10, 20, 30, 15, 5}
   for _, d := range data {
      root = insert(root, d)
      fmt.Printf("Inserted: %d\n", d)
   }
   fmt.Println("\nIn-order Traversal:")
   inOrderTraversal(root)
}

Output

Inserted: 10
Inserted: 20
Inserted: 30
Inserted: 15
Inserted: 5
 
In-order Traversal:
5 (R) 10 (R) 15 (R) 20 (R) 30 (R)

Real Life Implementation

  • The Linux Kernel's Completely Fair Scheduler (CFS): The Completely Fair Scheduler (CFS) employed within the Linux kernel, plays a crucial role in task management and organization. CFS utilizes a Red-Black Tree data structure to allocate priorities to each task, enabling precise determination of the next task to execute while maintaining fairness in the treatment of all jobs in the long term.

  • Spell Checkers and Autocomplete Suggestions: Offering real-time suggestions and spell-checking requires efficient data structures. Red-Black Trees help to store word lists and dictionaries and their balanced tree structures allow quick searches for accurate spellings and suggestions.

Conclusion

Efficient operations and balanced height are maintained through a color-coded node self-balancing binary search tree known as a Red-Black Tree. In this article, we provide the simplified programs to implement a red-black tree in golanguage and illustrate the insertion process, demonstrating the data structure balance's importance for optimal performance. Its ability to support crucial operations while maintaining balance makes Red-Black Trees a preferred choice in databases, memory allocation, and language libraries.

Updated on: 18-Oct-2023

55 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements