Golang 程序实现 treap

go programmingserver side programmingprogramming

在本文中,我们将使用两种不同的方法探索 Golang 中 Treap 数据结构的实现。Treap 是二叉搜索树和二叉堆的组合,使其成为一种有效的数据结构,用于维护一组有序元素,同时确保优先级平衡。第一种方法将使用递归方法来构建和维护 Treap,而第二种方法将实现迭代方法。下面的示例展示了随机二叉搜索树的创建和遍历,

解释

Treap 是另外两种结构(二叉搜索树和二叉堆)的酷炫组合。这种组合为我们提供了一种按顺序组织一堆项目的方法,同时还确保事物保持平衡和高效。我们在下图中表示了一个 treap −

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

在上述结构中,每个节点都包含值优先级对。此处值的放置方式使得值保持二叉搜索树属性,并且优先级可以保持最大堆属性。

语法

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

语法表示使用递归方法实现 Treap 的 TreapNode 结构。TreapNode 包含三个字段:key(节点的值)、priority(用于维护堆属性的随机生成的值)以及分别指向其左子节点和右子节点的左指针和右指针。这种递归实现确保 Treap 保持平衡,并遵循二叉搜索树和二叉堆的属性。

算法

  • 如果根为空,则使用给定的键和优先级创建一个新节点,并将其设置为 Treap 的根。

  • 如果要插入的键小于当前节点的键,则递归将其插入左子树。

  • 如果要插入的键大于当前节点的键,则递归将其插入右子树。

  • 插入左子树或右子树后,执行旋转以保持 Treap 的堆属性。如果当前节点的优先级大于其左子节点的优先级,则执行右旋转。如果当前节点的优先级大于其右子节点的优先级,则进行左旋转。

  • 更新从根到插入节点的路径中节点的大小或其他辅助信息。

示例 1

在此示例中,我们将使用 Golang 中的递归插入在 Go 中实现 Treap。我们定义一个 Node 结构来表示 Treap 中的每个节点。InsertRecursive 函数以给定的键和优先级递归地将新节点插入 Treap,同时保持 BST 和最大堆属性。

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("中序遍历:")
	InOrderTraversal(root)
}

输出

中序遍历:
(3, 50) (5, 87) (7, 23) (10, 5) (12, 45) (15, 68) (17, 57)

示例 2

在此示例中,我们将使用 Golang 中的迭代插入在 Go 中实现 Treap。Node 结构和 InsertIterative 函数与递归方法类似,但我们使用循环和堆栈的迭代方法在插入期间维护 BST 和最大堆属性。

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("按顺序遍历:")
	InOrderTraversal(root)
}

输出

按顺序遍历:
(3, 50) (5, 87) (12, 45) (15, 68) (17, 57)

实际实现

操作系统中的动态优先级队列

操作系统通常需要管理具有不同优先级的进程或任务。 Treap 数据结构可用于高效管理动态优先级队列。每个进程/任务都表示为 Treap 中的一个节点,其中键对应于优先级,优先级对应于堆属性。这样可以快速插入、删除和检索具有最高优先级的进程。由于优先级动态变化,Treap 的自平衡特性可确保高优先级任务得到有效处理,使其成为多任务操作系统中调度算法的合适选择。

广告平台中的在线广告投放

在在线广告平台中,需要根据出价金额、相关性和用户参与度等各种因素向用户投放和展示广告。可以使用 Treap 来管理广告显示的顺序。每个广告都表示为一个节点,以出价金额为键,以随机生成的值作为优先级。这可确保出价较高的广告获得优先权,同时仍在投放中提供一定程度的随机性,从而实现公平的广告轮换。

结论

本文展示了使用两种不同方法在 Go 中实现 Treap 的示例:递归和迭代。Treap 有效地结合了二叉搜索树和二叉堆的属性,提供了一组具有平衡优先级的有序元素。递归方法提供了一种构建和维护 Treap 的直接方法,而迭代方法则可以优化更大数据集的性能。


相关文章