Skip to content

Commit

Permalink
feat: add Set method. Closes #1
Browse files Browse the repository at this point in the history
  • Loading branch information
rdleal committed Dec 20, 2023
1 parent e53fffb commit eaf390e
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 2 deletions.
34 changes: 34 additions & 0 deletions kpq/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,37 @@ func Example() {
// Key: "key2", Value: 30
// Key 'key3' exists: true
}

func ExampleKeyedPriorityQueue_Set() {
cmp := func(a, b int) bool {
return a < b
}
pq := kpq.NewKeyedPriorityQueue[string](cmp)

// Insert elements onto the priority queue
pq.Push("second", 42)
pq.Push("first", 30)
pq.Push("last", 50)

// Updates an element
pq.Set("last", 20)

k, v, ok := pq.Pop()
if !ok {
log.Fatal("priority queue is empty")
}

fmt.Printf("Key: %q, Value: %d\n", k, v)

// Inserts a new element
pq.Set("new_first", 1)
k, v, ok = pq.Pop()
if !ok {
log.Fatal("priority queue is empty")
}

fmt.Printf("Key: %q, Value: %d\n", k, v)
// Output:
// Key: "last", Value: 20
// Key: "new_first", Value: 1
}
27 changes: 25 additions & 2 deletions kpq/keyed_priority_queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,16 @@ func (pq *KeyedPriorityQueue[K, V]) Push(k K, v V) error {
return newKeyAlreadyExistsError(k)
}

pq.push(k, v)
return nil
}

func (pq *KeyedPriorityQueue[K, V]) push(k K, v V) {
n := len(pq.pm)
pq.pm = append(pq.pm, k)
pq.im[k] = n
pq.vals[k] = v
pq.swim(n)
return nil
}

// Pop removes and returns the highest priority key and value from the priority queue.
Expand All @@ -129,6 +133,20 @@ func (pq *KeyedPriorityQueue[K, V]) Pop() (K, V, bool) {
return k, v, true
}

// Set inserts a new entry in the priority queue with the given key and value,
// if the key is not present in it; otherwise, it updates the priority value associated with the given key.
func (pq *KeyedPriorityQueue[K, V]) Set(k K, v V) {
pq.mu.Lock()
defer pq.mu.Unlock()

if i, ok := pq.im[k]; ok {
pq.update(k, v, i)
return
}

pq.push(k, v)
}

// Update changes the priority value associated with the given key k to the given value v.
// If there's no key k in the priority queue, it returns a KeyNotFoundError error.
func (pq *KeyedPriorityQueue[K, V]) Update(k K, v V) error {
Expand All @@ -139,10 +157,15 @@ func (pq *KeyedPriorityQueue[K, V]) Update(k K, v V) error {
if !ok {
return newKeyNotFoundError(k)
}

pq.update(k, v, i)
return nil
}

func (pq *KeyedPriorityQueue[K, V]) update(k K, v V, i int) {
pq.vals[k] = v
pq.swim(i)
pq.sink(i, len(pq.vals))
return nil
}

// Peek returns the highest priority key and value from the priority queue.
Expand Down
43 changes: 43 additions & 0 deletions kpq/keyed_priority_queue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,49 @@ func TestKeyedPriorityQueue_IsEmpty(t *testing.T) {
}
}

func TestKeyedPriorityQueue_Set(t *testing.T) {
pq := NewKeyedPriorityQueue[string](func(x, y int) bool {
return x < y
})

items := []struct {
key string
val int
}{
{key: "fourth", val: 10},
{key: "second", val: 8},
{key: "third", val: 9},
{key: "first", val: 6},
{key: "last", val: 20},
}

for _, item := range items {
err := pq.Push(item.key, item.val)
if err != nil {
t.Fatalf("Push(%v, %v): got unexpected error %v", item.key, item.val, err)
}
}

testCases := []struct {
k string
v int
}{
{"last", 5},
{"new_first", 1},
}

for _, tc := range testCases {
t.Run(tc.k, func(t *testing.T) {
pq.Set(tc.k, tc.v)

if got, _ := pq.PeekValue(); got != tc.v {
t.Errorf("pq.PeekValue(): got value %d; want %d", got, tc.v)
}
})
}

}

func benchmarkKeyedPriorityQueue_PushPop(b *testing.B, n int) {
pq := NewKeyedPriorityQueue[int](func(a, b int) bool {
return a > b
Expand Down

0 comments on commit eaf390e

Please sign in to comment.