diff options
| author | 2026-03-29 14:14:21 +0000 | |
|---|---|---|
| committer | 2026-03-29 14:14:21 +0000 | |
| commit | 69452f58fb0d6c1ed561df1e25efe51e5b3089fd (patch) | |
| tree | 3e9cf39ffc197acca3da05bc4162581767ac2b64 /internal/priorityqueue | |
| parent | commitquery: Use internal/heap for the priority queue (diff) | |
| signature | No signature | |
internal/priorityqueue: Actually just make our own priority queue
Diffstat (limited to 'internal/priorityqueue')
| -rw-r--r-- | internal/priorityqueue/len.go | 6 | ||||
| -rw-r--r-- | internal/priorityqueue/new.go | 6 | ||||
| -rw-r--r-- | internal/priorityqueue/pop.go | 21 | ||||
| -rw-r--r-- | internal/priorityqueue/push.go | 7 | ||||
| -rw-r--r-- | internal/priorityqueue/queue | 0 | ||||
| -rw-r--r-- | internal/priorityqueue/queue.go | 7 | ||||
| -rw-r--r-- | internal/priorityqueue/queue_test.go | 35 | ||||
| -rw-r--r-- | internal/priorityqueue/sift_down.go | 23 | ||||
| -rw-r--r-- | internal/priorityqueue/sift_up.go | 13 |
9 files changed, 118 insertions, 0 deletions
diff --git a/internal/priorityqueue/len.go b/internal/priorityqueue/len.go new file mode 100644 index 00000000..aca8e0ce --- /dev/null +++ b/internal/priorityqueue/len.go @@ -0,0 +1,6 @@ +package priorityqueue + +// Len reports the number of queued items. +func (queue *Queue[T]) Len() int { + return len(queue.items) +} diff --git a/internal/priorityqueue/new.go b/internal/priorityqueue/new.go new file mode 100644 index 00000000..bf1c1819 --- /dev/null +++ b/internal/priorityqueue/new.go @@ -0,0 +1,6 @@ +package priorityqueue + +// New builds one empty priority queue ordered by less. +func New[T any](less func(left, right T) bool) *Queue[T] { + return &Queue[T]{less: less} +} diff --git a/internal/priorityqueue/pop.go b/internal/priorityqueue/pop.go new file mode 100644 index 00000000..2190b065 --- /dev/null +++ b/internal/priorityqueue/pop.go @@ -0,0 +1,21 @@ +package priorityqueue + +// Pop removes one highest-priority item. +func (queue *Queue[T]) Pop() (T, bool) { + if len(queue.items) == 0 { + var zero T + + return zero, false + } + + last := len(queue.items) - 1 + top := queue.items[0] + queue.items[0] = queue.items[last] + queue.items = queue.items[:last] + + if len(queue.items) > 0 { + queue.siftDown(0) + } + + return top, true +} diff --git a/internal/priorityqueue/push.go b/internal/priorityqueue/push.go new file mode 100644 index 00000000..d0c6cadd --- /dev/null +++ b/internal/priorityqueue/push.go @@ -0,0 +1,7 @@ +package priorityqueue + +// Push inserts one item. +func (queue *Queue[T]) Push(item T) { + queue.items = append(queue.items, item) + queue.siftUp(len(queue.items) - 1) +} diff --git a/internal/priorityqueue/queue b/internal/priorityqueue/queue new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/internal/priorityqueue/queue diff --git a/internal/priorityqueue/queue.go b/internal/priorityqueue/queue.go new file mode 100644 index 00000000..279a400f --- /dev/null +++ b/internal/priorityqueue/queue.go @@ -0,0 +1,7 @@ +package priorityqueue + +// Queue is one slice-backed priority queue. +type Queue[T any] struct { + items []T + less func(left, right T) bool +} diff --git a/internal/priorityqueue/queue_test.go b/internal/priorityqueue/queue_test.go new file mode 100644 index 00000000..acb4f3e8 --- /dev/null +++ b/internal/priorityqueue/queue_test.go @@ -0,0 +1,35 @@ +package priorityqueue_test + +import ( + "slices" + "testing" + + "codeberg.org/lindenii/furgit/internal/priorityqueue" +) + +func TestQueueAscending(t *testing.T) { + t.Parallel() + + queue := priorityqueue.New(func(left, right int) bool { + return left < right + }) + + for _, value := range []int{5, 1, 4, 3, 2} { + queue.Push(value) + } + + var got []int + for queue.Len() > 0 { + value, ok := queue.Pop() + if !ok { + t.Fatal("Pop should succeed") + } + + got = append(got, value) + } + + want := []int{1, 2, 3, 4, 5} + if !slices.Equal(got, want) { + t.Fatalf("pop order = %v, want %v", got, want) + } +} diff --git a/internal/priorityqueue/sift_down.go b/internal/priorityqueue/sift_down.go new file mode 100644 index 00000000..83e3fd40 --- /dev/null +++ b/internal/priorityqueue/sift_down.go @@ -0,0 +1,23 @@ +package priorityqueue + +func (queue *Queue[T]) siftDown(idx int) { + for { + left := idx*2 + 1 + if left >= len(queue.items) { + return + } + + best := left + right := left + 1 + if right < len(queue.items) && queue.less(queue.items[right], queue.items[left]) { + best = right + } + + if !queue.less(queue.items[best], queue.items[idx]) { + return + } + + queue.items[idx], queue.items[best] = queue.items[best], queue.items[idx] + idx = best + } +} diff --git a/internal/priorityqueue/sift_up.go b/internal/priorityqueue/sift_up.go new file mode 100644 index 00000000..7ff4453f --- /dev/null +++ b/internal/priorityqueue/sift_up.go @@ -0,0 +1,13 @@ +package priorityqueue + +func (queue *Queue[T]) siftUp(idx int) { + for idx > 0 { + parent := (idx - 1) / 2 + if !queue.less(queue.items[idx], queue.items[parent]) { + return + } + + queue.items[idx], queue.items[parent] = queue.items[parent], queue.items[idx] + idx = parent + } +} |
