Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

queue.gno

2.39 Kb · 95 lines
 1package dijkstra
 2
 3// queue is the frontier: a binary min-heap of node indices ordered by their
 4// current distance, with a position table so a node already in the heap can be
 5// moved up when its distance improves.
 6//
 7// The alternative, pushing a second entry and discarding stale pops, is
 8// shorter and is what a generic priority queue forces on you. It also lets the
 9// heap grow to one entry per arc, which is the size this package refuses to
10// let a caller guess at: here the heap holds at most one entry per node, so
11// MaxNodes bounds the memory and MaxEdges bounds only the work.
12//
13// Ordering is total: distance first, then node index. Node indices are
14// assigned in the order AddNode saw them, so an equal-distance tie resolves to
15// the order the caller built the graph in, identically on every machine.
16type queue struct {
17	heap []int // heap positions -> node index
18	pos  []int // node index -> heap position, -1 when not queued
19	dist []int // the live distance table, read, never written
20}
21
22func newQueue(n int, dist []int) *queue {
23	q := &queue{dist: dist, pos: make([]int, n)}
24	for i := 0; i < n; i++ {
25		q.pos[i] = -1
26	}
27	return q
28}
29
30func (q *queue) empty() bool { return len(q.heap) == 0 }
31
32func (q *queue) less(a, b int) bool {
33	if q.dist[a] != q.dist[b] {
34		return q.dist[a] < q.dist[b]
35	}
36	return a < b
37}
38
39func (q *queue) swap(i, j int) {
40	q.heap[i], q.heap[j] = q.heap[j], q.heap[i]
41	q.pos[q.heap[i]] = i
42	q.pos[q.heap[j]] = j
43}
44
45// push queues a node whose distance has just become finite.
46func (q *queue) push(node int) {
47	q.heap = append(q.heap, node)
48	q.pos[node] = len(q.heap) - 1
49	q.up(len(q.heap) - 1)
50}
51
52// decreased re-sifts a queued node after its distance dropped.
53func (q *queue) decreased(node int) { q.up(q.pos[node]) }
54
55// pop removes and returns the closest outstanding node.
56func (q *queue) pop() int {
57	top := q.heap[0]
58	last := len(q.heap) - 1
59	q.swap(0, last)
60	q.heap = q.heap[:last]
61	q.pos[top] = -1
62	if last > 0 {
63		q.down(0)
64	}
65	return top
66}
67
68func (q *queue) up(i int) {
69	for i > 0 {
70		parent := (i - 1) / 2
71		if !q.less(q.heap[i], q.heap[parent]) {
72			break
73		}
74		q.swap(i, parent)
75		i = parent
76	}
77}
78
79func (q *queue) down(i int) {
80	n := len(q.heap)
81	for {
82		small := i
83		if l := 2*i + 1; l < n && q.less(q.heap[l], q.heap[small]) {
84			small = l
85		}
86		if r := 2*i + 2; r < n && q.less(q.heap[r], q.heap[small]) {
87			small = r
88		}
89		if small == i {
90			return
91		}
92		q.swap(i, small)
93		i = small
94	}
95}