Golang program to implement a treap


In this article, we will explore the implementation of a Treap data structure in Golang using two different methods. A Treap is a combination of a binary search tree and a binary heap, making it an efficient data structure for maintaining a set of ordered elements while also ensuring balanced priority. The first method will utilise a recursive approach for building and maintaining the Treap, while the second method will implement an iterative approach. The examples below showcase the creation and traversal of a randomised binary search tree,

Explanation

A Treap is a cool combination of two other structures, a binary search tree and a binary heap. This combination gives us a way to organize a bunch of items in order, while also making sure that things stay balanced and efficient. We have represented a treap in below diagram −

Value-Priority Pairs: (Value:Priority)
   (10:8)
     /   \
(5:15)  (20:10)
           /   \
      (17:5)  (25:2)

In the above structure each node contains the value priority pair.Here the values are placed in such a way that the value maintains binary search tree property, and max heap property can be maintained on priority.

Syntax

type TreapNode struct{ key, priority int; left, right *TreapNode }

The syntax represents a TreapNode structure used to implement a Treap using a recursive approach. A TreapNode contains three fields: key (the value of the node), priority (a randomly generated value for maintaining the heap property), and left and right pointers pointing to its left and right children, respectively. This recursive implementation ensures the Treap remains balanced and follows the properties of both a binary search tree and a binary heap.

Algorithm

  • If the root is null, create a new node with the given key and priority, and set it as the root of the Treap.

  • If the key to be inserted is less than the key of the current node, recursively insert it into the left subtree.

  • If the key to be inserted is greater than the key of the current node, recursively insert it into the right subtree.

  • After inserting into the left or right subtree, perform a rotation to maintain the heap property of the Treap. If the priority of the current node is greater than the priority of its left child, do a right rotation. If the priority of the current node is greater than the priority of its right child, do a left rotation.

  • Update the size or other auxiliary information of the nodes in the path from the root to the inserted node.

Example 1

In this example, we will implement a Treap in go using recursive insertion in Golang. We define a Node struct to represent each node in the Treap. The InsertRecursive function recursively inserts a new node with the given key and priority into the Treap while maintaining the BST and max-heap properties.

package main

import (
	"fmt"
	"math/rand"
)

type Node struct {
	key     int
	priority int
	left    *Node
	right   *Node
}

func NewNode(key, priority int) *Node {
	return &Node{
		key:     key,
		priority: priority,
	}
}

func InsertRecursive(root *Node, key, priority int) *Node {
	if root == nil {
		return NewNode(key, priority)
	}

	if key < root.key {
		root.left = InsertRecursive(root.left, key, priority)
		if root.left.priority > root.priority {
			root = rotateRight(root)
		}
	} else if key > root.key {
		root.right = InsertRecursive(root.right, key, priority)
		if root.right.priority > root.priority {
			root = rotateLeft(root)
		}
	}

	return root
}

func rotateRight(y *Node) *Node {
	x := y.left
	y.left = x.right
	x.right = y
	return x
}

func rotateLeft(x *Node) *Node {
	y := x.right
	x.right = y.left
	y.left = x
	return y
}

func InOrderTraversal(root *Node) {
	if root != nil {
		InOrderTraversal(root.left)
		fmt.Printf("(%d, %d) ", root.key, root.priority)
		InOrderTraversal(root.right)
	}
}

func main() {
	rand.Seed(42)

	var root *Node
	keys := []int{10, 5, 15, 3, 7, 12, 17}

	for _, key := range keys {
		priority := rand.Intn(100)
		root = InsertRecursive(root, key, priority)
	}

	fmt.Println("In-Order Traversal:")
	InOrderTraversal(root)
}

Output

In-Order Traversal:
(3, 50) (5, 87) (7, 23) (10, 5) (12, 45) (15, 68) (17, 57) 

Example 2

In this example, we will implement a Treap in go using iterative insertion in Golang. The Node struct and InsertIterative function are similar to the recursive method, but we use an iterative approach with a loop and a stack to maintain the BST and max-heap properties during insertion.

package main

import (
	"fmt"
	"math/rand"
)

type Node struct {
	key     int
	priority int
	left    *Node
	right   *Node
}

func NewNode(key, priority int) *Node {
	return &Node{
		key:     key,
		priority: priority,
	}
}

func InsertIterative(root *Node, key, priority int) *Node {
	newNode := NewNode(key, priority)

	var parent *Node
	curr := root

	for curr != nil && curr.priority >= priority {
		parent = curr
		if key < curr.key {
			curr = curr.left
		} else {
			curr = curr.right
		}
	}

	if parent == nil {
		root = newNode
	} else if key < parent.key {
		parent.left = newNode
	} else {
		parent.right = newNode
	}

	return root
}

func InOrderTraversal(root *Node) {
	if root != nil {
		InOrderTraversal(root.left)
		fmt.Printf("(%d, %d) ", root.key, root.priority)
		InOrderTraversal(root.right)
	}
}

func main() {
	rand.Seed(42)

	var root *Node
	keys := []int{10, 5, 15, 3, 7, 12, 17}

	for _, key := range keys {
		priority := rand.Intn(100)
		root = InsertIterative(root, key, priority)
	}

	fmt.Println("In-Order Traversal:")
	InOrderTraversal(root)
}

Output

In-Order Traversal:
(3, 50) (5, 87) (12, 45) (15, 68) (17, 57)

Real life implementation

Dynamic Priority Queues in Operating Systems

Operating systems often need to manage processes or tasks with varying priorities. The Treap data structure can be used to efficiently manage dynamic priority queues. Each process/task is represented as a node in the Treap, where the key corresponds to the priority and the priority corresponds to the heap property. This enables quick insertion, deletion, and retrieval of processes with the highest priority. As priorities change dynamically, the Treap's self-balancing properties ensure that high-priority tasks are efficiently processed, making it a suitable choice for scheduling algorithms in multitasking operating systems.

Online Ad Placement in Advertising Platforms

In online advertising platforms, ads need to be placed and displayed to users based on various factors like bid amount, relevance, and user engagement. A Treap can be employed to manage the order in which ads are displayed. Each ad is represented as a node with the bid amount as the key and a randomly generated value as the priority. This ensures that ads with higher bids are prioritized while still providing some level of randomness in the placement, leading to fair ad rotations.

Conclusion

The article showcases examples to implement a Treap in go using two different methods: recursive and iterative. The Treap efficiently combines the properties of a binary search tree and a binary heap, providing an ordered set of elements with balanced priorities. The recursive method offers a straightforward approach to build and maintain the Treap, while the iterative method optimises performance for larger datasets.

Updated on: 05-Sep-2023

50 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements