priority queue
This commit is contained in:
parent
39992e2a9c
commit
68deb1be7a
4 changed files with 169 additions and 0 deletions
7
go.mod
7
go.mod
|
@ -1,3 +1,10 @@
|
||||||
module github.com/fotonmoton/algorithms
|
module github.com/fotonmoton/algorithms
|
||||||
|
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.0 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/stretchr/testify v1.7.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
||||||
|
)
|
||||||
|
|
10
go.sum
Normal file
10
go.sum
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
93
sorting/priority_queue.go
Normal file
93
sorting/priority_queue.go
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
package sorting
|
||||||
|
|
||||||
|
type PriorityQueue[T any] interface {
|
||||||
|
top() T
|
||||||
|
insert(T)
|
||||||
|
delete() T
|
||||||
|
size() int
|
||||||
|
isEmpty() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type priorityQueue[T any] struct {
|
||||||
|
n int
|
||||||
|
heap []T
|
||||||
|
less func(T, T) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPQ[T any](less func(T, T) bool) PriorityQueue[T] {
|
||||||
|
return &priorityQueue[T]{
|
||||||
|
n: 0,
|
||||||
|
less: less,
|
||||||
|
// First element is not used
|
||||||
|
// to make equation "next = current * 2" work
|
||||||
|
heap: make([]T, 1, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pq *priorityQueue[T]) top() T {
|
||||||
|
// After all operations biggest element
|
||||||
|
// should be always at the beginning of the array
|
||||||
|
return pq.heap[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pq *priorityQueue[T]) insert(item T) {
|
||||||
|
// TODO: increase by square when capacity is full
|
||||||
|
pq.heap = append(pq.heap, item)
|
||||||
|
pq.n++
|
||||||
|
pq.swim(pq.n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pq *priorityQueue[T]) delete() T {
|
||||||
|
top := pq.top()
|
||||||
|
pq.swap(1, pq.n)
|
||||||
|
pq.heap = pq.heap[:pq.n]
|
||||||
|
pq.n--
|
||||||
|
pq.sink(1)
|
||||||
|
return top
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pq *priorityQueue[_]) size() int {
|
||||||
|
return pq.n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pq *priorityQueue[_]) isEmpty() bool {
|
||||||
|
return pq.n == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pq *priorityQueue[_]) swap(i, j int) {
|
||||||
|
pq.heap[i], pq.heap[j] = pq.heap[j], pq.heap[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pq *priorityQueue[T]) swim(start int) {
|
||||||
|
for k := start; k > 1 && pq.less(pq.heap[k/2], pq.heap[k]); k = k / 2 {
|
||||||
|
pq.swap(k/2, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pq *priorityQueue[T]) sink(k int) {
|
||||||
|
// While k is a parent with some children
|
||||||
|
for 2*k <= pq.n {
|
||||||
|
|
||||||
|
// First child of a parent k
|
||||||
|
j := 2 * k
|
||||||
|
|
||||||
|
// If first child is less than second
|
||||||
|
// we choose second one for exchange.
|
||||||
|
// Parent should be swapped with biggest child
|
||||||
|
if j < pq.n && pq.less(pq.heap[j], pq.heap[j+1]) {
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
|
||||||
|
// If parent is already bigger than biggest child
|
||||||
|
// we found the position
|
||||||
|
if !pq.less(pq.heap[k], pq.heap[j]) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// swap parent node with child
|
||||||
|
pq.swap(j, k)
|
||||||
|
|
||||||
|
// child node is a new parent
|
||||||
|
k = j
|
||||||
|
}
|
||||||
|
}
|
59
sorting/priority_queue_test.go
Normal file
59
sorting/priority_queue_test.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package sorting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
var intCompare = func(t1, t2 int) bool { return t1 < t2 }
|
||||||
|
|
||||||
|
func TestNew(t *testing.T) {
|
||||||
|
pq := NewPQ(intCompare)
|
||||||
|
assert.NotNil(t, pq)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSize(t *testing.T) {
|
||||||
|
pq := NewPQ(intCompare)
|
||||||
|
assert.Equal(t, 0, pq.size())
|
||||||
|
pq.insert(1)
|
||||||
|
assert.Equal(t, 1, pq.size())
|
||||||
|
pq.delete()
|
||||||
|
assert.Equal(t, 0, pq.size())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsEmpty(t *testing.T) {
|
||||||
|
pq := NewPQ(intCompare)
|
||||||
|
assert.Equal(t, true, pq.isEmpty())
|
||||||
|
pq.insert(1)
|
||||||
|
assert.Equal(t, false, pq.isEmpty())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInsert(t *testing.T) {
|
||||||
|
pq := NewPQ(intCompare)
|
||||||
|
pq.insert(1)
|
||||||
|
assert.Equal(t, 1, pq.top())
|
||||||
|
pq.insert(4)
|
||||||
|
assert.Equal(t, 4, pq.top())
|
||||||
|
pq.insert(3)
|
||||||
|
assert.Equal(t, 4, pq.top())
|
||||||
|
pq.insert(5)
|
||||||
|
assert.Equal(t, 5, pq.top())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDelete(t *testing.T) {
|
||||||
|
pq := NewPQ(intCompare)
|
||||||
|
pq.insert(1)
|
||||||
|
pq.insert(2)
|
||||||
|
pq.insert(6)
|
||||||
|
pq.insert(5)
|
||||||
|
pq.insert(4)
|
||||||
|
pq.insert(3)
|
||||||
|
assert.Equal(t, 6, pq.delete())
|
||||||
|
assert.Equal(t, 5, pq.delete())
|
||||||
|
assert.Equal(t, 4, pq.delete())
|
||||||
|
assert.Equal(t, 3, pq.delete())
|
||||||
|
assert.Equal(t, 2, pq.delete())
|
||||||
|
assert.Equal(t, 1, pq.delete())
|
||||||
|
}
|
Loading…
Reference in a new issue