chore(day17): implement fibHeap for faster priority queue
Go Test / build (pull_request) Successful in 37s
Go Bump / bump (push) Successful in 7s
Go Test / build (push) Successful in 39s

This commit was merged in pull request #21.
This commit is contained in:
xuu
2024-01-09 13:53:30 -07:00
parent 7585526634
commit 7d7402f054
5 changed files with 347 additions and 84 deletions
+147 -30
View File
@@ -85,36 +85,35 @@ func TestPriorityQueue(t *testing.T) {
is := is.New(t)
type elem [2]int
less := func(a, b elem) bool {
return a[0] < b[0]
less := func(b, a *elem) bool {
return (*a)[0] < (*b)[0]
}
pq := aoc.PriorityQueue(less)
pq.Enqueue(elem{1, 4})
pq.Enqueue(elem{3, 2})
pq.Enqueue(elem{2, 3})
pq.Enqueue(elem{4, 1})
pq.Insert(&elem{1, 4})
pq.Insert(&elem{3, 2})
pq.Insert(&elem{2, 3})
pq.Insert(&elem{4, 1})
v, ok := pq.Dequeue()
is.True(ok)
is.Equal(v, elem{4, 1})
v := pq.ExtractMin()
is.True(v != nil)
is.Equal(v, &elem{4, 1})
v, ok = pq.Dequeue()
is.True(ok)
is.Equal(v, elem{3, 2})
v = pq.ExtractMin()
is.True(v != nil)
is.Equal(v, &elem{3, 2})
v, ok = pq.Dequeue()
is.True(ok)
is.Equal(v, elem{2, 3})
v = pq.ExtractMin()
is.True(v != nil)
is.Equal(v, &elem{2, 3})
v, ok = pq.Dequeue()
is.True(ok)
is.Equal(v, elem{1, 4})
v = pq.ExtractMin()
is.True(v != nil)
is.Equal(v, &elem{1, 4})
v, ok = pq.Dequeue()
is.True(!ok)
is.Equal(v, elem{})
v = pq.ExtractMin()
is.True(v == nil)
}
func TestSet(t *testing.T) {
@@ -140,7 +139,7 @@ func ExamplePriorityQueue() {
pt int
score int
}
less := func(a, b memo) bool { return b.score < a.score }
less := func(a, b *memo) bool { return a.score < b.score }
adj := map[int][][2]int{
0: {{1, 2}, {2, 6}},
@@ -156,10 +155,10 @@ func ExamplePriorityQueue() {
dist := aoc.DefaultMap[int](int(^uint(0) >> 1))
dist.Set(0, 0)
pq.Enqueue(memo{0, 0})
pq.Insert(&memo{0, 0})
for !pq.IsEmpty() {
m, _ := pq.Dequeue()
m := pq.ExtractMin()
u := m.pt
if visited.Has(u) {
@@ -175,7 +174,7 @@ func ExamplePriorityQueue() {
if !visited.Has(v) && du+w < dv {
dist.Set(v, du+w)
pq.Enqueue(memo{v, du + w})
pq.Insert(&memo{v, du + w})
}
}
}
@@ -199,14 +198,14 @@ func ExamplePriorityQueue() {
func TestStack(t *testing.T) {
is := is.New(t)
s := aoc.Stack(1,2,3,4)
s := aoc.Stack(1, 2, 3, 4)
is.True(!s.IsEmpty())
is.Equal(s.Pop(), 4)
is.Equal(s.Pop(), 3)
is.Equal(s.Pop(), 2)
is.Equal(s.Pop(), 1)
is.True(s.IsEmpty())
s.Push(4,3,2,1)
s.Push(4, 3, 2, 1)
is.True(!s.IsEmpty())
is.Equal(s.Pop(), 1)
is.Equal(s.Pop(), 2)
@@ -230,7 +229,125 @@ func TestGraph(t *testing.T) {
9: {6, 0, 8},
}
g := aoc.Graph(aoc.WithAdjacencyList[int,int](adjacencyList))
is.Equal(g.Neighbors(1), []int{2,4})
g := aoc.Graph(aoc.WithAdjacencyList[int, int](adjacencyList))
is.Equal(g.Neighbors(1), []int{2, 4})
is.Equal(map[int][]int(g.AdjacencyList()), adjacencyList)
}
}
func ExampleFibHeap() {
type memo struct {
pt int
score int
}
less := func(a, b *memo) bool { return (*a).score < (*b).score }
adj := map[int][][2]int{
0: {{1, 2}, {2, 6}},
1: {{3, 5}},
2: {{3, 8}},
3: {{4, 10}, {5, 15}},
4: {{6, 2}},
5: {{6, 6}},
}
pq := aoc.FibHeap(less)
visited := aoc.Set([]int{}...)
dist := aoc.DefaultMap[int](int(^uint(0) >> 1))
dist.Set(0, 0)
pq.Insert(&memo{0, 0})
for !pq.IsEmpty() {
m := pq.ExtractMin()
u := m.pt
if visited.Has(u) {
continue
}
visited.Add(u)
du, _ := dist.Get(u)
for _, edge := range adj[u] {
v, w := edge[0], edge[1]
dv, _ := dist.Get(v)
if !visited.Has(v) && du+w < dv {
dist.Set(v, du+w)
pq.Insert(&memo{v, du + w})
}
}
}
items := dist.Items()
sort.Slice(items, func(i, j int) bool { return items[i].K < items[j].K })
for _, v := range items {
fmt.Printf("point %d is %d steps away.\n", v.K, v.V)
}
// Output:
// point 0 is 0 steps away.
// point 1 is 2 steps away.
// point 2 is 6 steps away.
// point 3 is 7 steps away.
// point 4 is 17 steps away.
// point 5 is 22 steps away.
// point 6 is 19 steps away.
}
func TestFibHeap(t *testing.T) {
is := is.New(t)
type elem [2]int
less := func(a, b *elem) bool {
return (*a)[0] < (*b)[0]
}
pq := aoc.FibHeap(less)
pq.Insert(&elem{1, 4})
pq.Insert(&elem{3, 2})
pq.Insert(&elem{2, 3})
pq.Insert(&elem{4, 1})
v := pq.ExtractMin()
is.True(v != nil)
is.Equal(v, &elem{1, 4})
pq.Insert(&elem{5, 8})
pq.Insert(&elem{6, 7})
pq.Insert(&elem{7, 6})
pq.Insert(&elem{8, 5})
v = pq.ExtractMin()
is.True(v != nil)
is.Equal(v, &elem{2, 3})
v = pq.ExtractMin()
is.True(v != nil)
is.Equal(v, &elem{3, 2})
v = pq.ExtractMin()
is.True(v != nil)
is.Equal(v, &elem{4, 1})
v = pq.ExtractMin()
is.True(v != nil)
is.Equal(v, &elem{5, 8})
m := aoc.FibHeap(less)
m.Insert(&elem{12, 9})
m.Insert(&elem{11, 10})
m.Insert(&elem{10, 11})
m.Insert(&elem{9, 12})
pq.Merge(m)
var keys []int
for !pq.IsEmpty() {
v := pq.ExtractMin()
fmt.Println(v)
keys = append(keys, v[0])
}
is.Equal(keys, []int{6, 7, 8, 9, 10, 11, 12})
}