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 | ||||
| 
 | ||||
| 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…
	
	Add table
		
		Reference in a new issue