mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
adt: implement a binary MinHeap data structure (#12956)
This commit is contained in:
parent
8764a3a973
commit
485b392cb3
@ -22,6 +22,8 @@ println(stack)
|
||||
## Currently Implemented Datatypes:
|
||||
|
||||
- [x] Linked list
|
||||
- [x] Doubly linked list
|
||||
- [x] Stack (LIFO)
|
||||
- [x] Queue (FIFO)
|
||||
- [x] Min heap (priority queue)
|
||||
- [ ] ...
|
||||
|
84
vlib/adt/heap.v
Normal file
84
vlib/adt/heap.v
Normal file
@ -0,0 +1,84 @@
|
||||
module adt
|
||||
|
||||
// MinHeap is a binary minimum heap data structure.
|
||||
pub struct MinHeap<T> {
|
||||
mut:
|
||||
data []T
|
||||
}
|
||||
|
||||
// insert adds an element to the heap.
|
||||
pub fn (mut heap MinHeap<T>) insert(item T) {
|
||||
// push item to the end of the array
|
||||
heap.data << item
|
||||
// swap the new node with its parent until the heap is in order
|
||||
mut child := heap.data.len - 1
|
||||
mut parent := heap.parent(child)
|
||||
for heap.data[parent] > heap.data[child] {
|
||||
heap.data[parent], heap.data[child] = heap.data[child], heap.data[parent]
|
||||
child = parent
|
||||
parent = heap.parent(child)
|
||||
}
|
||||
}
|
||||
|
||||
// pop removes the top-most element from the heap.
|
||||
pub fn (mut heap MinHeap<T>) pop() ?T {
|
||||
if heap.data.len == 0 {
|
||||
return none
|
||||
} else if heap.data.len == 1 {
|
||||
return heap.data.pop()
|
||||
}
|
||||
item := heap.data[0]
|
||||
// move last element to root
|
||||
heap.data[0] = heap.data.pop()
|
||||
// swap the new root with its minimum child until the heap is in order
|
||||
mut parent := 0
|
||||
mut left := heap.left_child(parent) or { return item }
|
||||
mut right := heap.right_child(parent) or { left }
|
||||
for heap.data[parent] > heap.data[left] || heap.data[parent] > heap.data[right] {
|
||||
// choose min for min heap
|
||||
swap := if heap.data[left] <= heap.data[right] { left } else { right }
|
||||
heap.data[parent], heap.data[swap] = heap.data[swap], heap.data[parent]
|
||||
parent = swap
|
||||
left = heap.left_child(parent) or { break }
|
||||
right = heap.right_child(parent) or { left }
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
// peek gets the top-most element from the heap without removing it.
|
||||
pub fn (heap MinHeap<T>) peek() ?T {
|
||||
if heap.data.len == 0 {
|
||||
return none
|
||||
}
|
||||
return heap.data[0]
|
||||
}
|
||||
|
||||
// len returns the number of elements in the heap.
|
||||
pub fn (heap MinHeap<T>) len() int {
|
||||
return heap.data.len
|
||||
}
|
||||
|
||||
// left_child is a helper function that returns the index of the left
|
||||
// child given a parent idx, or none if there is no left child.
|
||||
fn (heap MinHeap<T>) left_child(idx int) ?int {
|
||||
child := 2 * idx + 1
|
||||
if child >= heap.data.len {
|
||||
return none
|
||||
}
|
||||
return child
|
||||
}
|
||||
|
||||
// right_child is a helper function that returns the index of the right
|
||||
// child given a parent idx, or none if there is no right child.
|
||||
fn (heap MinHeap<T>) right_child(idx int) ?int {
|
||||
child := 2 * idx + 2
|
||||
if child >= heap.data.len {
|
||||
return none
|
||||
}
|
||||
return child
|
||||
}
|
||||
|
||||
// parent is a helper function that returns the parent index of the child.
|
||||
fn (heap MinHeap<T>) parent(idx int) int {
|
||||
return (idx - 1) / 2
|
||||
}
|
68
vlib/adt/heap_test.v
Normal file
68
vlib/adt/heap_test.v
Normal file
@ -0,0 +1,68 @@
|
||||
module adt
|
||||
|
||||
fn test_min_heap() ? {
|
||||
mut heap := MinHeap<int>{}
|
||||
heap.insert(2)
|
||||
heap.insert(0)
|
||||
heap.insert(8)
|
||||
heap.insert(4)
|
||||
heap.insert(1)
|
||||
|
||||
assert heap.pop() ? == 0
|
||||
assert heap.pop() ? == 1
|
||||
assert heap.pop() ? == 2
|
||||
assert heap.pop() ? == 4
|
||||
assert heap.pop() ? == 8
|
||||
if _ := heap.pop() {
|
||||
panic('expected none')
|
||||
}
|
||||
}
|
||||
|
||||
struct Item {
|
||||
data string
|
||||
priority int
|
||||
}
|
||||
|
||||
fn (lhs Item) < (rhs Item) bool {
|
||||
return rhs.priority < lhs.priority
|
||||
}
|
||||
|
||||
fn test_min_heap_custom() ? {
|
||||
mut heap := MinHeap<Item>{}
|
||||
heap.insert(Item{'buz', 10})
|
||||
heap.insert(Item{'qux', 0})
|
||||
heap.insert(Item{'baz', 50})
|
||||
heap.insert(Item{'foo', 100})
|
||||
heap.insert(Item{'bar', 80})
|
||||
|
||||
assert heap.pop() ?.data == 'foo'
|
||||
assert heap.pop() ?.data == 'bar'
|
||||
assert heap.pop() ?.data == 'baz'
|
||||
assert heap.pop() ?.data == 'buz'
|
||||
assert heap.pop() ?.data == 'qux'
|
||||
if _ := heap.pop() {
|
||||
panic('expected none')
|
||||
}
|
||||
}
|
||||
|
||||
fn test_heap_len() ? {
|
||||
mut heap := MinHeap<int>{}
|
||||
heap.insert(2)
|
||||
assert heap.len() == 1
|
||||
heap.insert(0)
|
||||
heap.insert(8)
|
||||
heap.insert(4)
|
||||
assert heap.len() == 4
|
||||
heap.insert(1)
|
||||
|
||||
assert heap.len() == 5
|
||||
heap.pop() ?
|
||||
heap.pop() ?
|
||||
heap.pop() ?
|
||||
assert heap.len() == 2
|
||||
heap.pop() ?
|
||||
heap.pop() ?
|
||||
assert heap.len() == 0
|
||||
heap.pop() or {}
|
||||
assert heap.len() == 0
|
||||
}
|
Loading…
Reference in New Issue
Block a user