├── .all-contributorsrc ├── .gitignore ├── .travis.yml ├── AUTHORS.md ├── CONTRIBUTING.md ├── Gopkg.lock ├── Gopkg.toml ├── LICENSE ├── Makefile ├── README.md ├── appveyor.yml ├── binomial ├── binomial_heap.go └── binomial_heap_test.go ├── doc.go ├── example ├── leftist │ └── leftist.go ├── pairing │ └── pairing.go ├── rank_pairing │ └── rank_pairing.go ├── skew │ └── skew.go └── treap │ └── treap.go ├── fibonacci ├── heap.go └── heap_test.go ├── heap.go ├── leftist ├── leftist_heap.go └── leftist_heap_test.go ├── pairing ├── pairing_heap.go └── pairing_heap_test.go ├── rank_pairing ├── rank_pairing_heap.go └── rank_pairing_heap_test.go ├── skew ├── skew_heap.go └── skew_heap_test.go ├── treap ├── treap.go └── treap_test.go └── version.go /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "go-heaps", 3 | "projectOwner": "theodesp", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "README.md" 8 | ], 9 | "imageSize": 100, 10 | "commit": false, 11 | "contributors": [ 12 | { 13 | "login": "mb-14", 14 | "name": "Miroojin Bakshi", 15 | "avatar_url": "https://avatars1.githubusercontent.com/u/1137632?v=4", 16 | "profile": "http://mb-14.github.io", 17 | "contributions": [ 18 | "code" 19 | ] 20 | }, 21 | { 22 | "login": "Syfaro", 23 | "name": "Syfaro", 24 | "avatar_url": "https://avatars2.githubusercontent.com/u/1369709?v=4", 25 | "profile": "https://syfaro.net", 26 | "contributions": [ 27 | "code" 28 | ] 29 | }, 30 | { 31 | "login": "theodesp", 32 | "name": "Theofanis Despoudis", 33 | "avatar_url": "https://avatars0.githubusercontent.com/u/328805?v=4", 34 | "profile": "https://github.com/theodesp", 35 | "contributions": [ 36 | "code" 37 | ] 38 | }, 39 | { 40 | "login": "radlinskii", 41 | "name": "Radliński Ignacy", 42 | "avatar_url": "https://avatars0.githubusercontent.com/u/26116041?v=4", 43 | "profile": "https://www.linkedin.com/in/ignacy-radlinski", 44 | "contributions": [ 45 | "code" 46 | ] 47 | }, 48 | { 49 | "login": "DonMcNamara", 50 | "name": "Don McNamara", 51 | "avatar_url": "https://avatars3.githubusercontent.com/u/1152286?v=4", 52 | "profile": "https://github.com/DonMcNamara", 53 | "contributions": [ 54 | "infra" 55 | ] 56 | }, 57 | { 58 | "login": "koneko096", 59 | "name": "Afrizal Fikri", 60 | "avatar_url": "https://avatars3.githubusercontent.com/u/9217338?v=4", 61 | "profile": "https://koneko096.github.io/", 62 | "contributions": [ 63 | "code" 64 | ] 65 | }, 66 | { 67 | "login": "lhauspie", 68 | "name": "Logan HAUSPIE", 69 | "avatar_url": "https://avatars1.githubusercontent.com/u/25682509?v=4", 70 | "profile": "https://github.com/lhauspie", 71 | "contributions": [ 72 | "code" 73 | ] 74 | }, 75 | { 76 | "login": "erjiaqing", 77 | "name": "Song Guo", 78 | "avatar_url": "https://avatars3.githubusercontent.com/u/5517838?v=4", 79 | "profile": "https://ejq.me/", 80 | "contributions": [ 81 | "code" 82 | ] 83 | }, 84 | { 85 | "login": "safwan-moha", 86 | "name": "Safwan Mohammed", 87 | "avatar_url": "https://avatars0.githubusercontent.com/u/7314967?v=4", 88 | "profile": "https://github.com/safwan-moha", 89 | "contributions": [ 90 | "test", 91 | "code" 92 | ] 93 | } 94 | ], 95 | "contributorsPerLine": 7 96 | } 97 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Go template 3 | # Binaries for programs and plugins 4 | *.exe 5 | *.dll 6 | *.so 7 | *.dylib 8 | 9 | # Test binary, build with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 16 | .glide/ 17 | .idea/ 18 | /vendor 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | os: 4 | - linux 5 | 6 | # This project contains references to the absolute GitHub path, 7 | # e.g. github.com/theodesp/go-heaps/leftist. 8 | # That means, by default, if someone forks the repo and makes changes, Travis 9 | # won't pass for the branch on their own repo. To fix that, we move the 10 | # directory. 11 | # From: https://github.com/cloudflare/cfssl/blob/c71f2083af21ebe304311b33831fbbecf42c2738/.travis.yml#L22-L29 12 | before_install: 13 | - make debs 14 | - mkdir -p $TRAVIS_BUILD_DIR $GOPATH/src/github.com/theodesp 15 | - test ! -d $GOPATH/src/github.com/theodesp/go-heaps && mv $TRAVIS_BUILD_DIR $GOPATH/src/github.com/theodesp/go-heaps || true 16 | 17 | # test on the two most recent releases and tip 18 | go: 19 | - "1.10.x" 20 | - "1.11.x" 21 | - "tip" 22 | 23 | matrix: 24 | allow_failures: 25 | - go: tip 26 | 27 | script: 28 | - make test 29 | 30 | after_success: 31 | - bash <(curl -s https://codecov.io/bash) 32 | 33 | notifications: 34 | email: false 35 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | # Credits 2 | 3 | ## Development Lead 4 | 5 | - [theodesp](https://github.com/theodesp) 6 | 7 | ## Contributors 8 | 9 | None yet. Why not be the first? 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given. 4 | 5 | You can contribute in many ways: 6 | 7 | ## Types of Contributions 8 | 9 | ### Report Bugs 10 | 11 | Report bugs at https://github.com/theodesp/go-heaps/issues. 12 | 13 | If you are reporting a bug, please include: 14 | 15 | * Your operating system name and version. 16 | * Any details about your local setup that might be helpful in troubleshooting. 17 | * Detailed steps to reproduce the bug. 18 | 19 | ### Fix Bugs 20 | 21 | Look through the GitHub issues for bugs. Anything tagged with "bug" 22 | is open to whoever wants to implement it. 23 | 24 | ### Implement Features 25 | 26 | Look through the GitHub issues for features. Anything tagged with "feature" 27 | is open to whoever wants to implement it. 28 | 29 | ### Write Documentation 30 | 31 | go-heaps could always use more documentation, whether as part of the 32 | official go-heaps docs, in docstrings, or even on the web in blog posts, 33 | articles, and such. 34 | 35 | ### Submit Feedback 36 | 37 | The best way to send feedback is to file an issue at https://github.com/theodesp/go-heaps/issues. 38 | 39 | If you are proposing a feature: 40 | 41 | * Explain in detail how it would work. 42 | * Keep the scope as narrow as possible, to make it easier to implement. 43 | * Remember that this is a volunteer-driven project, and that contributions 44 | are welcome :) 45 | 46 | ## Get Started! 47 | 48 | Ready to contribute? Here's how to set up `go-heaps` for local development. 49 | 50 | 1. Fork the `go-heaps` repo on GitHub. 51 | 2. Clone your fork locally:: 52 | 53 | $ git clone git@github.com:your_name_here/go-heaps.git 54 | 55 | 3. Create a branch for local development:: 56 | 57 | $ git checkout -b name-of-your-bugfix-or-feature 58 | 59 | Now you can make your changes locally. 60 | 61 | 4. When you're done making changes, check that your changes pass the tests:: 62 | 63 | $ make test 64 | 65 | 6. Commit your changes and push your branch to GitHub:: 66 | 67 | $ git add . 68 | $ git commit -m "Your detailed description of your changes." 69 | $ git push origin name-of-your-bugfix-or-feature 70 | 71 | 7. Submit a pull request through the GitHub website. 72 | 73 | Pull Request Guidelines 74 | ----------------------- 75 | 76 | Before you submit a pull request, check that it meets these guidelines: 77 | 78 | 1. The pull request should include tests. 79 | 2. If the pull request adds functionality, the docs should be updated. Put 80 | your new functionality into a function with a docstring, and add the 81 | feature to the list in README.md. -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" 6 | name = "github.com/davecgh/go-spew" 7 | packages = ["spew"] 8 | pruneopts = "UT" 9 | revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" 10 | version = "v1.1.1" 11 | 12 | [[projects]] 13 | digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" 14 | name = "github.com/pmezard/go-difflib" 15 | packages = ["difflib"] 16 | pruneopts = "UT" 17 | revision = "792786c7400a136282c1664665ae0a8db921c6c2" 18 | version = "v1.0.0" 19 | 20 | [[projects]] 21 | digest = "1:5110e3d4f130772fd39e6ce8208ad1955b242ccfcc8ad9d158857250579c82f4" 22 | name = "github.com/stretchr/testify" 23 | packages = [ 24 | "assert", 25 | "require", 26 | "suite", 27 | ] 28 | pruneopts = "UT" 29 | revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686" 30 | version = "v1.2.2" 31 | 32 | [solve-meta] 33 | analyzer-name = "dep" 34 | analyzer-version = 1 35 | input-imports = [ 36 | "github.com/stretchr/testify/assert", 37 | "github.com/stretchr/testify/suite", 38 | ] 39 | solver-name = "gps-cdcl" 40 | solver-version = 1 41 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | # Gopkg.toml example 2 | # 3 | # Refer to https://golang.github.io/dep/docs/Gopkg.toml.html 4 | # for detailed Gopkg.toml documentation. 5 | # 6 | # required = ["github.com/user/thing/cmd/thing"] 7 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] 8 | # 9 | # [[constraint]] 10 | # name = "github.com/user/project" 11 | # version = "1.0.0" 12 | # 13 | # [[constraint]] 14 | # name = "github.com/user/project2" 15 | # branch = "dev" 16 | # source = "github.com/myfork/project2" 17 | # 18 | # [[override]] 19 | # name = "github.com/x/y" 20 | # version = "2.4.0" 21 | # 22 | # [prune] 23 | # non-go = false 24 | # go-tests = true 25 | # unused-packages = true 26 | 27 | 28 | [prune] 29 | go-tests = true 30 | unused-packages = true 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright 2018 Theo Despoudis. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | .PHONY: format 3 | format: 4 | @find . -type f -name "*.go*" -print0 | xargs -0 gofmt -s -w 5 | 6 | .PHONY: debs 7 | debs: 8 | GOPATH=$(GOPATH) go get -u github.com/stretchr/testify 9 | GOPATH=$(GOPATH) go get -u github.com/fortytw2/leaktest 10 | 11 | .PHONY: test 12 | test: 13 | -rm coverage.txt 14 | @for package in $$(go list ./... | grep -v example) ; do \ 15 | GOPATH=$(GOPATH) go test -race -coverprofile=profile.out -covermode=atomic $$package ; \ 16 | if [ -f profile.out ]; then \ 17 | cat profile.out >> coverage.txt ; \ 18 | rm profile.out ; \ 19 | fi \ 20 | done 21 | 22 | .PHONY: bench 23 | bench: 24 | GOPATH=$(GOPATH) go test -bench=. -check.b -benchmem 25 | 26 | # Clean junk 27 | .PHONY: clean 28 | clean: 29 | GOPATH=$(GOPATH) go clean ./... 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | go-heaps 2 | [![All Contributors](https://img.shields.io/badge/all_contributors-9-orange.svg?style=flat-square)](#contributors) 3 | --- 4 | 5 | GoDoc 6 | 7 | 8 | 9 | License 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Reference implementations of heap data structures in Go 21 | 22 | ## Installation 23 | ```bash 24 | $ go get -u github.com/theodesp/go-heaps 25 | ``` 26 | 27 | ## Contents 28 | 29 | **Heaps** 30 | 31 | * [Pairing Heap](https://en.wikipedia.org/wiki/Pairing_heap): A pairing heap is a type of heap data structure with relatively simple implementation and excellent practical amortized performance. 32 | * [Leftist Heap](https://www.geeksforgeeks.org/leftist-tree-leftist-heap/): a variant of a binary heap. Every node has an s-value which is the distance to the nearest leaf. In contrast to a binary heap, a leftist tree attempts to be very unbalanced. 33 | * [Skew Heap](https://en.wikipedia.org/wiki/Skew_heap): A skew heap (or self-adjusting heap) is a heap data structure implemented as a binary tree. Skew heaps are advantageous because of their ability to merge more quickly than binary heaps. 34 | * [Fibonacci Heap](https://en.wikipedia.org/wiki/Fibonacci_heap): a Fibonacci heap is a data structure for priority queue operations, consisting of a collection of heap-ordered trees. It has a better amortized running time than many other priority queue data structures including the binary heap and binomial heap. 35 | * [Binomial Heap](https://www.geeksforgeeks.org/binomial-heap-2/): A Binomial Heap is a collection of Binomial Trees. A Binomial Heap is a set of Binomial Trees where each Binomial Tree follows Min Heap property. And there can be at most one Binomial Tree of any degree. 36 | * [Treap Heap](https://en.wikipedia.org/wiki/Treap): A Treap and the randomized binary search tree are two closely related forms of binary search tree data structures that maintain a dynamic set of ordered keys and allow binary searches among the keys. 37 | * [Rank Pairing Heap](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.153.4644&rep=rep1&type=pdf): A heap (priority queue) implementation that combines the asymptotic efficiency of Fibonacci heaps with much of the simplicity of pairing heaps 38 | 39 | ## Usage 40 | 41 | ```go 42 | package main 43 | 44 | import ( 45 | "github.com/theodesp/go-heaps" 46 | pairingHeap "github.com/theodesp/go-heaps/pairing" 47 | "fmt" 48 | ) 49 | 50 | func main() { 51 | heap := pairingHeap.New() 52 | heap.Insert(go_heaps.Integer(4)) 53 | heap.Insert(go_heaps.Integer(3)) 54 | heap.Insert(go_heaps.Integer(2)) 55 | heap.Insert(go_heaps.Integer(5)) 56 | 57 | fmt.Println(heap.DeleteMin()) // 2 58 | fmt.Println(heap.DeleteMin()) // 3 59 | fmt.Println(heap.DeleteMin()) // 4 60 | fmt.Println(heap.DeleteMin()) // 5 61 | } 62 | 63 | ``` 64 | 65 | ## Complexity 66 | | Operation | Pairing | Leftist | Skew | Fibonacci | Binomial | Treap | 67 | | ------------- |:-------------:|:-------------:|:-------------:|:-------------:|:-------------:|:-------------:| 68 | | FindMin | Θ(1) | Θ(1) | Θ(1) | Θ(1) | Θ(log n) | O(n) | 69 | | DeleteMin | O(log n) | O(log n) | O(log n) | O(log n) | Θ(log n) | O(n) | 70 | | Insert | Θ(1) | O(log n) | O(log n) | Θ(1) | Θ(1) | O(n) | 71 | | Find | O(n) | | | | | | 72 | | Delete | O(n) | | O(log n) | O(n) | Θ(log n) | O(n) | 73 | | Adjust | O(n) | | O(log n) | O(n) | Θ(log n) | O(n) | 74 | | Meld | Θ(1) | | | | | | 75 | 76 | | Operation | Rank Pairing | 77 | | ------------- |:-------------:| 78 | | FindMin | Θ(1) | 79 | | DeleteMin | O(log n) | 80 | | Insert | Θ(1) | 81 | | Find | O(n) | 82 | | Delete | O(n) | 83 | | Adjust | O(n) | 84 | | Meld | Θ(1) | 85 | 86 | 87 | 88 | ## Contributors 89 | 90 | 91 | Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)): 92 | 93 | 94 | 95 |
Miroojin Bakshi
Miroojin Bakshi

💻
Syfaro
Syfaro

💻
Theofanis Despoudis
Theofanis Despoudis

💻
Radliński Ignacy
Radliński Ignacy

💻
Don McNamara
Don McNamara

🚇
Afrizal Fikri
Afrizal Fikri

💻
Logan HAUSPIE
Logan HAUSPIE

💻
Song Guo
Song Guo

💻
Safwan Mohammed
Safwan Mohammed

⚠️ 💻
96 | 97 | 98 | 99 | This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome! 100 | 101 | 102 | ## LICENCE 103 | Copyright © 2017 Theo Despoudis MIT license -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # version format 2 | version: "{build}" 3 | 4 | # Operating system (build VM template) 5 | os: Windows Server 2012 R2 6 | 7 | shallow_clone: true 8 | clone_folder: c:\gopath\src\github.com\theodesp\go-heaps 9 | 10 | init: 11 | - git config --global core.autocrlf input 12 | 13 | branches: 14 | only: 15 | - master 16 | 17 | # environment variables 18 | environment: 19 | GOPATH: c:\gopath 20 | GOVERSION: 1.9 21 | 22 | # scripts that run after cloning repository 23 | install: 24 | - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% 25 | - go version 26 | - go env 27 | - go get ./... github.com/stretchr/testify 28 | - go get -u github.com/fortytw2/leaktest 29 | 30 | # to run your custom scripts instead of automatic MSBuild 31 | build_script: 32 | - go test -cpu=2 -race -v ./... 33 | 34 | test: off 35 | deploy: off -------------------------------------------------------------------------------- /binomial/binomial_heap.go: -------------------------------------------------------------------------------- 1 | // Package binomial implements a Binomial heap Data structure 2 | // 3 | // Structure is not thread safe. 4 | // 5 | // Reference: https://en.wikipedia.org/wiki/Binomial_heap 6 | package binomial 7 | 8 | import ( 9 | "math" 10 | 11 | heap "github.com/theodesp/go-heaps" 12 | ) 13 | 14 | // BinomialHeap is an implementation of a Binomial Heap. 15 | type BinomialHeap struct { 16 | root *node 17 | } 18 | 19 | //node is a leaf in the heap 20 | type node struct { 21 | item heap.Item 22 | parent *node 23 | child *node 24 | sibling *node 25 | degree int 26 | } 27 | 28 | //Insert inserts the value to the BinomialHeap and returns the item 29 | // The complexity is O(log n). 30 | func (b *BinomialHeap) Insert(v heap.Item) heap.Item { 31 | n := node{item: v} 32 | tempHeap := &BinomialHeap{root: &n} 33 | b.root = b.union(tempHeap) 34 | return n.item 35 | } 36 | 37 | // DeleteMin removes the smallest item from the BinomialHeap and returns it 38 | // The complexity is O(log n). 39 | func (b *BinomialHeap) DeleteMin() heap.Item { 40 | if b.root == nil { 41 | return nil 42 | } 43 | 44 | min := b.root 45 | var minPrev *node 46 | next := min.sibling 47 | nextPrev := min 48 | 49 | for next != nil { 50 | if next.item.Compare(min.item) < 0 { 51 | min = next 52 | minPrev = nextPrev 53 | } 54 | nextPrev = next 55 | next = next.sibling 56 | } 57 | b.removeTreeRoot(min, minPrev) 58 | return min.item 59 | } 60 | 61 | // Deletes passed item from the heap. 62 | // The complexity is O(log n). 63 | func (p *BinomialHeap) Delete(item heap.Item) { 64 | found := p.findAny(item) 65 | next := found 66 | for next.parent != nil { 67 | temp := next.item 68 | next.item = next.parent.item 69 | next.parent.item = temp 70 | 71 | next = next.parent 72 | } 73 | next.item = heap.Integer(math.Inf(-1)) 74 | p.DeleteMin() 75 | } 76 | 77 | // FindAny returns the address of item in the heap. 78 | func (b *BinomialHeap) findAny(item heap.Item) *node { 79 | next := b.root 80 | backToParent := false 81 | 82 | for next != nil { 83 | if next.child != nil && !backToParent { 84 | if next.item == item { 85 | return next 86 | } 87 | next = next.child 88 | backToParent = false 89 | } else if next.sibling != nil { 90 | if next.item == item { 91 | return next 92 | } 93 | next = next.sibling 94 | backToParent = false 95 | } else if next.parent != nil { 96 | if next.item == item { 97 | return next 98 | } 99 | next = next.parent 100 | backToParent = true 101 | } else { 102 | next = nil 103 | } 104 | } 105 | return b.root 106 | } 107 | 108 | // FindMin returns the smallest item in the heap. 109 | // The complexity is O(log n). 110 | func (b *BinomialHeap) FindMin() heap.Item { 111 | if b.root == nil { 112 | return nil 113 | } 114 | min := b.root 115 | next := min.sibling 116 | 117 | for next != nil { 118 | if next.item.Compare(min.item) < 0 { 119 | min = next 120 | } 121 | next = next.sibling 122 | } 123 | 124 | return min.item 125 | } 126 | 127 | // Clear resets the current BinomialHeap 128 | func (b *BinomialHeap) Clear() { 129 | b.root = nil 130 | } 131 | 132 | func (b *BinomialHeap) union(heap *BinomialHeap) *node { 133 | newRoot := merge(b, heap) 134 | b.root = nil 135 | heap.root = nil 136 | if newRoot == nil { 137 | return nil 138 | } 139 | var prev *node 140 | curr := newRoot 141 | next := newRoot.sibling 142 | for next != nil { 143 | if curr.degree != next.degree || (next.sibling != nil && 144 | next.sibling.degree == curr.degree) { 145 | prev = curr 146 | curr = next 147 | } else { 148 | if curr.item.Compare(next.item) < 0 { 149 | curr.sibling = next.sibling 150 | linkNodes(curr, next) 151 | } else { 152 | if prev == nil { 153 | newRoot = next 154 | } else { 155 | prev.sibling = next 156 | } 157 | linkNodes(next, curr) 158 | curr = next 159 | } 160 | } 161 | next = curr.sibling 162 | } 163 | return newRoot 164 | } 165 | 166 | func (b *BinomialHeap) removeTreeRoot(root, prev *node) { 167 | // Remove root from the heap 168 | if root == b.root { 169 | b.root = root.sibling 170 | } else { 171 | prev.sibling = root.sibling 172 | } 173 | 174 | var newRoot *node 175 | child := root.child 176 | for child != nil { 177 | next := child.sibling 178 | child.sibling = newRoot 179 | child.parent = nil 180 | newRoot = child 181 | child = next 182 | } 183 | newHeap := &BinomialHeap{root: newRoot} 184 | b.root = b.union(newHeap) 185 | } 186 | 187 | func merge(a *BinomialHeap, b *BinomialHeap) *node { 188 | if a.root == nil { 189 | return b.root 190 | } 191 | if b.root == nil { 192 | return a.root 193 | } 194 | 195 | var root *node 196 | aNext := a.root 197 | bNext := b.root 198 | if aNext.degree <= bNext.degree { 199 | root = aNext 200 | aNext = aNext.sibling 201 | } else { 202 | root = bNext 203 | bNext = bNext.sibling 204 | } 205 | 206 | tail := root 207 | 208 | for aNext != nil && bNext != nil { 209 | if aNext.degree <= bNext.degree { 210 | tail.sibling = aNext 211 | aNext = aNext.sibling 212 | } else { 213 | tail.sibling = bNext 214 | bNext = bNext.sibling 215 | } 216 | 217 | tail = tail.sibling 218 | } 219 | 220 | if aNext != nil { 221 | tail.sibling = aNext 222 | } else { 223 | tail.sibling = bNext 224 | } 225 | 226 | return root 227 | } 228 | 229 | func linkNodes(a, b *node) { 230 | b.parent = a 231 | b.sibling = a.child 232 | a.child = b 233 | a.degree++ 234 | } 235 | -------------------------------------------------------------------------------- /binomial/binomial_heap_test.go: -------------------------------------------------------------------------------- 1 | package binomial 2 | 3 | import ( 4 | "sort" 5 | "testing" 6 | 7 | "github.com/theodesp/go-heaps" 8 | ) 9 | 10 | func TestLeftistHeapInteger(t *testing.T) { 11 | heap := &BinomialHeap{} 12 | 13 | numbers := []int{4, 3, 2, 5} 14 | 15 | for _, number := range numbers { 16 | heap.Insert(Int(number)) 17 | } 18 | 19 | sort.Ints(numbers) 20 | 21 | for _, number := range numbers { 22 | if Int(number) != heap.DeleteMin().(go_heaps.Integer) { 23 | t.Fail() 24 | } 25 | } 26 | } 27 | 28 | func TestBinomialHeapIntegerDelete(t *testing.T) { 29 | heap := &BinomialHeap{} 30 | 31 | numbers := []int{14, 112, 15, 16 , 71, 91, 1, 12, 23, 56, 34} 32 | 33 | for _, number := range numbers { 34 | heap.Insert(Int(number)) 35 | } 36 | 37 | heap.Delete(Int(15)) 38 | heap.Delete(Int(12)) 39 | 40 | numbers = RemoveInts(numbers, 15) 41 | numbers = RemoveInts(numbers, 12) 42 | sort.Ints(numbers) 43 | 44 | for _, number := range numbers { 45 | if Int(number) != heap.DeleteMin().(go_heaps.Integer) { 46 | t.Fail() 47 | } 48 | } 49 | } 50 | 51 | func TestBinomialHeapStringDelete(t *testing.T) { 52 | heap := &BinomialHeap{} 53 | 54 | strings := []string{"a", "ccc", "bb", "d"} 55 | 56 | for _, str := range strings { 57 | heap.Insert(Str(str)) 58 | } 59 | 60 | heap.Delete(Str("ccc")) 61 | 62 | strings = RemoveStrs(strings, "ccc") 63 | sort.Strings(strings) 64 | 65 | for _, str := range strings { 66 | if Str(str) != heap.DeleteMin().(go_heaps.String) { 67 | t.Fail() 68 | } 69 | } 70 | } 71 | 72 | func TestLeftistHeapString(t *testing.T) { 73 | heap := &BinomialHeap{} 74 | 75 | strs := []string{"a", "ccc", "bb", "d"} 76 | 77 | for _, str := range strs { 78 | heap.Insert(Str(str)) 79 | } 80 | 81 | sort.Strings(strs) 82 | 83 | for _, str := range strs { 84 | if Str(str) != heap.DeleteMin().(go_heaps.String) { 85 | t.Fail() 86 | } 87 | } 88 | } 89 | 90 | func RemoveInts(s []int, hay int) []int { 91 | sort.Ints(s) 92 | i := sort.SearchInts(s, hay) 93 | s[i] = s[len(s)-1] 94 | return s[:len(s)-1] 95 | } 96 | 97 | func RemoveStrs(s []string, hay string) []string { 98 | sort.Strings(s) 99 | i := sort.SearchStrings(s, hay) 100 | s[i] = s[len(s)-1] 101 | return s[:len(s)-1] 102 | } 103 | 104 | func Int(value int) go_heaps.Integer { 105 | return go_heaps.Integer(value) 106 | } 107 | 108 | func Str(value string) go_heaps.String { 109 | return go_heaps.String(value) 110 | } 111 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | package go_heaps 2 | -------------------------------------------------------------------------------- /example/leftist/leftist.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/theodesp/go-heaps" 7 | "github.com/theodesp/go-heaps/leftist" 8 | ) 9 | 10 | func main() { 11 | heap := leftist.New() 12 | heap.Insert(Int(4)) 13 | heap.Insert(Int(19)) 14 | heap.Insert(Int(8)) 15 | heap.Insert(Int(27)) 16 | heap.Insert(Int(20)) 17 | heap.Insert(Int(12)) 18 | heap.Insert(Int(15)) 19 | heap.Insert(Int(6)) 20 | heap.Insert(Int(7)) 21 | heap.Insert(Int(8)) 22 | 23 | fmt.Println(heap.DeleteMin()) // 4 24 | fmt.Println(heap.DeleteMin()) // 6 25 | fmt.Println(heap.DeleteMin()) // 7 26 | fmt.Println(heap.DeleteMin()) // 8 27 | } 28 | 29 | func Int(value int) go_heaps.Integer { 30 | return go_heaps.Integer(value) 31 | } 32 | -------------------------------------------------------------------------------- /example/pairing/pairing.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/theodesp/go-heaps" 5 | "github.com/theodesp/go-heaps/pairing" 6 | "fmt" 7 | ) 8 | 9 | func main() { 10 | heap := pairing.New() 11 | heap.Insert(Int(4)) 12 | heap.Insert(Int(3)) 13 | heap.Insert(Int(2)) 14 | heap.Insert(Int(5)) 15 | 16 | fmt.Println(heap.DeleteMin()) // 2 17 | fmt.Println(heap.DeleteMin()) // 3 18 | fmt.Println(heap.DeleteMin()) // 4 19 | fmt.Println(heap.DeleteMin()) // 5 20 | } 21 | 22 | func Int(value int) go_heaps.Integer { 23 | return go_heaps.Integer(value) 24 | } -------------------------------------------------------------------------------- /example/rank_pairing/rank_pairing.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/theodesp/go-heaps" 7 | rpheap "github.com/theodesp/go-heaps/rank_pairing" 8 | ) 9 | 10 | func main() { 11 | heap := rpheap.New() 12 | heap.Insert(Int(4)) 13 | heap.Insert(Int(3)) 14 | heap.Insert(Int(2)) 15 | heap.Insert(Int(5)) 16 | 17 | fmt.Println(heap.DeleteMin()) // 2 18 | fmt.Println(heap.DeleteMin()) // 3 19 | fmt.Println(heap.DeleteMin()) // 4 20 | fmt.Println(heap.DeleteMin()) // 5 21 | 22 | heap1 := rpheap.New() 23 | heap2 := rpheap.New() 24 | heap1.Insert(Int(2)) 25 | heap1.Insert(Int(8)) 26 | heap1.Insert(Int(5)) 27 | heap1.Insert(Int(7)) 28 | heap2.Insert(Int(4)) 29 | heap2.Insert(Int(9)) 30 | heap2.Insert(Int(6)) 31 | 32 | heap1.Meld(heap2) 33 | 34 | fmt.Println(heap1.DeleteMin()) // 2 35 | fmt.Println(heap1.DeleteMin()) // 4 36 | fmt.Println(heap1.DeleteMin()) // 5 37 | //... 38 | } 39 | 40 | func Int(value int) go_heaps.Integer { 41 | return go_heaps.Integer(value) 42 | } 43 | -------------------------------------------------------------------------------- /example/skew/skew.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/theodesp/go-heaps" 5 | skewheap "github.com/theodesp/go-heaps/skew" 6 | "fmt" 7 | ) 8 | 9 | func main() { 10 | heap := skewheap.New() 11 | heap.Insert(Int(4)) 12 | heap.Insert(Int(19)) 13 | heap.Insert(Int(8)) 14 | heap.Insert(Int(27)) 15 | heap.Insert(Int(20)) 16 | heap.Insert(Int(12)) 17 | heap.Insert(Int(15)) 18 | heap.Insert(Int(6)) 19 | heap.Insert(Int(7)) 20 | heap.Insert(Int(8)) 21 | 22 | fmt.Println(heap.DeleteMin()) // 4 23 | fmt.Println(heap.DeleteMin()) // 6 24 | fmt.Println(heap.DeleteMin()) // 7 25 | fmt.Println(heap.DeleteMin()) // 8 26 | } 27 | 28 | func Int(value int) go_heaps.Integer { 29 | return go_heaps.Integer(value) 30 | } 31 | -------------------------------------------------------------------------------- /example/treap/treap.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | goheap "github.com/theodesp/go-heaps" 7 | "github.com/theodesp/go-heaps/treap" 8 | ) 9 | 10 | func main() { 11 | heap := treap.New() 12 | heap.Insert(goheap.Integer(4)) 13 | heap.Insert(goheap.Integer(19)) 14 | heap.Insert(goheap.Integer(8)) 15 | heap.Insert(goheap.Integer(27)) 16 | heap.Insert(goheap.Integer(20)) 17 | heap.Insert(goheap.Integer(12)) 18 | heap.Insert(goheap.Integer(15)) 19 | heap.Insert(goheap.Integer(6)) 20 | heap.Insert(goheap.Integer(7)) 21 | heap.Insert(goheap.Integer(8)) 22 | 23 | fmt.Println(heap.DeleteMin()) // 4 24 | fmt.Println(heap.DeleteMin()) // 6 25 | fmt.Println(heap.DeleteMin()) // 7 26 | fmt.Println(heap.DeleteMin()) // 8 27 | fmt.Println(heap.DeleteMin()) // 8 28 | fmt.Println(heap.DeleteMin()) // 12 29 | fmt.Println(heap.DeleteMin()) // 15 30 | fmt.Println(heap.DeleteMin()) // 19 31 | fmt.Println(heap.DeleteMin()) // 20 32 | fmt.Println(heap.DeleteMin()) // 27 33 | } 34 | -------------------------------------------------------------------------------- /fibonacci/heap.go: -------------------------------------------------------------------------------- 1 | // Package fibonacci implements a Fibonacci FibonacciHeap Data structure 2 | // Reference: https://en.wikipedia.org/wiki/Fibonacci_heap 3 | // Implementation from Introduction to Algorithms by T. Cormen 4 | package fibonacci 5 | 6 | import ( 7 | heap "github.com/theodesp/go-heaps" 8 | ) 9 | 10 | // FibonacciHeap is a implementation of Fibonacci heap. 11 | type FibonacciHeap struct { 12 | root *node 13 | } 14 | 15 | // node holds structure of nodes inside Fibonacci heap. 16 | type node struct { 17 | item heap.Item 18 | prev, next, parent, child *node 19 | isMarked bool 20 | degree int 21 | } 22 | 23 | // New creates and returns a new, empty heap. 24 | func New() *FibonacciHeap { 25 | return &FibonacciHeap{root: nil} 26 | } 27 | 28 | // Insert inserts a new node, with predeclared item, to the heap. 29 | func (fh *FibonacciHeap) Insert(item heap.Item) heap.Item { 30 | n := &node{item: item, isMarked: false} 31 | 32 | fh.insertRoot(n) 33 | return item 34 | } 35 | 36 | // FindMin returns the minimum item. 37 | func (fh *FibonacciHeap) FindMin() heap.Item { 38 | if fh.root == nil { 39 | return nil 40 | } 41 | return fh.root.item 42 | } 43 | 44 | // DeleteMin extracts the node with minimum item from a heap 45 | // and returns the minimum item. 46 | func (fh *FibonacciHeap) DeleteMin() heap.Item { 47 | r := fh.root 48 | if r == nil { 49 | return nil 50 | } 51 | for { 52 | // add r children to fh's root list 53 | if x := r.child; x != nil { 54 | x.parent = nil 55 | if x.next != x { 56 | r.child = x.next 57 | x.next.prev = x.prev 58 | x.prev.next = x.next 59 | } else { 60 | r.child = nil 61 | } 62 | x.prev = r.prev 63 | x.next = r 64 | r.prev.next = x 65 | r.prev = x 66 | } else { 67 | break 68 | } 69 | } 70 | // remove r from fh's root list 71 | r.prev.next = r.next 72 | r.next.prev = r.prev 73 | 74 | if r == r.next { 75 | fh.root = nil 76 | } else { 77 | fh.root = r.next 78 | fh.consolidate() 79 | } 80 | 81 | return r.item 82 | } 83 | 84 | func (fh *FibonacciHeap) consolidate() { 85 | degreeToRoot := make(map[int]*node) 86 | w := fh.root 87 | last := w.prev 88 | for { 89 | r := w.next 90 | x := w 91 | d := x.degree 92 | for { 93 | if y, ok := degreeToRoot[d]; !ok { 94 | break 95 | } else { 96 | if y.item.Compare(x.item) < 0 { 97 | y, x = x, y 98 | } 99 | link(x, y) 100 | delete(degreeToRoot, d) 101 | d++ 102 | } 103 | } 104 | degreeToRoot[d] = x 105 | if w == last { 106 | break 107 | } 108 | w = r 109 | } 110 | fh.root = nil 111 | for _, v := range degreeToRoot { 112 | fh.insertRoot(v) 113 | } 114 | 115 | } 116 | 117 | // Clear resets heap. 118 | func (fh *FibonacciHeap) Clear() { 119 | fh.root = nil 120 | } 121 | 122 | func link(x, y *node) { 123 | // remove y from fh's root list 124 | y.next.prev = y.prev 125 | y.prev.next = y.next 126 | // make y a child of x and increase degree of x 127 | y.parent = x 128 | if x.child == nil { 129 | x.child = y 130 | y.prev = y 131 | y.next = y 132 | } else { 133 | insert(x.child, y) 134 | } 135 | 136 | y.isMarked = false 137 | } 138 | 139 | func (fh *FibonacciHeap) insertRoot(n *node) { 140 | if fh.root == nil { 141 | // create fh's root list containing only n 142 | n.prev = n 143 | n.next = n 144 | fh.root = n 145 | } else { 146 | // insert n to fh's root list 147 | insert(fh.root, n) 148 | if n.item.Compare(fh.root.item) < 0 { 149 | fh.root = n 150 | } 151 | } 152 | } 153 | 154 | func insert(x, y *node) { 155 | x.prev.next = y 156 | y.next = x 157 | y.prev = x.prev 158 | x.prev = y 159 | } 160 | 161 | /* 162 | // DecreaseKey decreases the key of given node. 163 | func (fh *FibonacciHeap) DecreaseKey(x *node, k heap.Item) { 164 | if x.item.Compare(k) < 0 { 165 | panic("new item is greater than the previous one") 166 | } 167 | x.item = k 168 | y := x.parent 169 | if y != nil && x.item.Compare(y.item) < 0 { 170 | fh.cut(x, y) 171 | fh.cascadingCut(y) 172 | } 173 | if x.item.Compare(fh.root.item) < 0 { 174 | fh.root = x 175 | } 176 | } 177 | 178 | func (fh *FibonacciHeap) cut(x, y *node) { 179 | // remove x from y's children list and decrement y's degree 180 | if x.next != x { 181 | y.child = x.next 182 | x.next.prev = x.prev 183 | x.prev.next = x.next 184 | } else { 185 | y.child = nil 186 | } 187 | y.degree-- 188 | // add x to fh's root list 189 | insert(fh.root, x) 190 | 191 | x.parent = nil 192 | x.isMarked = false 193 | } 194 | 195 | func (fh *FibonacciHeap) cascadingCut(y *node) { 196 | z := y.parent 197 | if z != nil { 198 | if !y.isMarked { 199 | y.isMarked = true 200 | } else { 201 | fh.cut(y, z) 202 | fh.cascadingCut(z) 203 | } 204 | } 205 | } 206 | */ 207 | -------------------------------------------------------------------------------- /fibonacci/heap_test.go: -------------------------------------------------------------------------------- 1 | package fibonacci 2 | 3 | import ( 4 | "sort" 5 | "testing" 6 | 7 | "github.com/theodesp/go-heaps" 8 | ) 9 | 10 | func TestFibonacciHeapInteger(t *testing.T) { 11 | heap := &FibonacciHeap{} 12 | 13 | numbers := []int{4, 3, 2, 5} 14 | 15 | for _, number := range numbers { 16 | heap.Insert(Int(number)) 17 | } 18 | 19 | sort.Ints(numbers) 20 | 21 | for _, number := range numbers { 22 | i := heap.DeleteMin().(go_heaps.Integer) 23 | if Int(number) != i { 24 | t.Fail() 25 | } 26 | } 27 | } 28 | 29 | func TestFibonacciHeapString(t *testing.T) { 30 | heap := &FibonacciHeap{} 31 | 32 | strs := []string{"a", "ccc", "bb", "d"} 33 | 34 | for _, str := range strs { 35 | heap.Insert(Str(str)) 36 | } 37 | 38 | sort.Strings(strs) 39 | 40 | for _, str := range strs { 41 | if Str(str) != heap.DeleteMin().(go_heaps.String) { 42 | t.Fail() 43 | } 44 | } 45 | } 46 | 47 | func TestFibonacciHeap(t *testing.T) { 48 | heap := &FibonacciHeap{} 49 | 50 | numbers := []int{4, 3, -1, 5, 9} 51 | 52 | for _, number := range numbers { 53 | heap.Insert(Int(number)) 54 | } 55 | 56 | if heap.FindMin() != Int(-1) { 57 | t.Fail() 58 | } 59 | 60 | heap.Clear() 61 | if heap.FindMin() != nil { 62 | t.Fail() 63 | } 64 | } 65 | 66 | func Int(value int) go_heaps.Integer { 67 | return go_heaps.Integer(value) 68 | } 69 | 70 | func Str(value string) go_heaps.String { 71 | return go_heaps.String(value) 72 | } 73 | -------------------------------------------------------------------------------- /heap.go: -------------------------------------------------------------------------------- 1 | package go_heaps 2 | 3 | // Interface is basic interface that all Heaps implement. 4 | type Interface interface { 5 | // Inserts an element to the heap and returns it 6 | Insert(v Item) Item 7 | 8 | // DeleteMin deletes and returns the smallest element 9 | DeleteMin() Item 10 | 11 | // FindMin returns the minimum element 12 | FindMin() Item 13 | 14 | // Removes all items 15 | Clear() 16 | } 17 | 18 | // Extended adds operations on heaps are often useful. 19 | type Extended interface { 20 | Interface 21 | // Return the heap formed by taking the union of the item disjoint 22 | // current heap and a 23 | Meld(a Interface) Interface 24 | 25 | // Adjusts the key of item old in heap h to new 26 | Adjust(old, new Item) Item 27 | 28 | // Delete arbitrary item from heap h. 29 | Delete(item Item) Item 30 | } 31 | 32 | // Item is the basic element that is inserted in a heap 33 | type Item interface { 34 | // Should return a number: 35 | // negative , if a < b 36 | // zero , if a == b 37 | // positive , if a > b 38 | Compare(than Item) int 39 | } 40 | 41 | // ItemIterator allows callers of Do to iterate in-order over portions of 42 | // the tree. When this function returns false, iteration will stop and the 43 | // function will immediately return. 44 | type ItemIterator func(item Item) bool 45 | 46 | // String implements the Item interface 47 | type String string 48 | 49 | // Integer implements the Item interface 50 | type Integer int 51 | 52 | func (a String) Compare(b Item) int { 53 | s1 := a 54 | s2 := b.(String) 55 | min := len(s2) 56 | if len(s1) < len(s2) { 57 | min = len(s1) 58 | } 59 | diff := 0 60 | for i := 0; i < min && diff == 0; i++ { 61 | diff = int(s1[i]) - int(s2[i]) 62 | } 63 | if diff == 0 { 64 | diff = len(s1) - len(s2) 65 | } 66 | if diff < 0 { 67 | return -1 68 | } 69 | if diff > 0 { 70 | return 1 71 | } 72 | return 0 73 | } 74 | 75 | func (a Integer) Compare(b Item) int { 76 | a1 := a 77 | a2 := b.(Integer) 78 | switch { 79 | case a1 > a2: 80 | return 1 81 | case a1 < a2: 82 | return -1 83 | default: 84 | return 0 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /leftist/leftist_heap.go: -------------------------------------------------------------------------------- 1 | package leftist 2 | 3 | import ( 4 | heap "github.com/theodesp/go-heaps" 5 | ) 6 | 7 | // Node is a leaf in the heap. 8 | type Node struct { 9 | item heap.Item 10 | left, right *Node 11 | s int // s-value (or rank) 12 | } 13 | 14 | // LeftistHeap is a leftist heap implementation. 15 | type LeftistHeap struct { 16 | root *Node 17 | } 18 | 19 | func mergeNodes(x, y *Node) *Node { 20 | if x == nil { 21 | return y 22 | } 23 | 24 | if y == nil { 25 | return x 26 | } 27 | // Compare the roots of two heaps. 28 | if x.item.Compare(y.item) > 0 { 29 | return merge(y, x) 30 | } else { 31 | return merge(x, y) 32 | } 33 | } 34 | 35 | func merge(x, y *Node) *Node { 36 | if x.left == nil { 37 | // left child doesn't exist, so move right child to the smallest key 38 | // to maintain the leftList invariant 39 | x.left = y 40 | x.right = nil 41 | } else { 42 | x.right = mergeNodes(x.right, y) 43 | // left child does exist, so compare s-values 44 | if x.left.s < x.right.s { 45 | x.left, x.right = x.right, x.left 46 | } 47 | // since we know the right child has the lower s-value, we can just 48 | // add one to its s-value 49 | x.s = x.right.s + 1 50 | } 51 | 52 | return x 53 | } 54 | 55 | // Init initializes or clears the LeftistHeap 56 | func (h *LeftistHeap) Init() *LeftistHeap { 57 | h.root = nil 58 | return h 59 | } 60 | 61 | // New returns an initialized LeftistHeap. 62 | func New() *LeftistHeap { return new(LeftistHeap).Init() } 63 | 64 | // Insert adds an item into the heap. 65 | // The complexity is O(log n) amortized. 66 | func (h *LeftistHeap) Insert(item heap.Item) heap.Item { 67 | h.root = mergeNodes(&Node{ 68 | item: item, 69 | }, h.root) 70 | 71 | return item 72 | } 73 | 74 | // DeleteMin deletes the minimum value and returns it. 75 | // The complexity is O(log n) amortized. 76 | func (h *LeftistHeap) DeleteMin() heap.Item { 77 | item := h.root.item 78 | 79 | h.root = mergeNodes(h.root.left, h.root.right) 80 | 81 | return item 82 | } 83 | 84 | // FindMin finds the minimum value. 85 | // The complexity is O(1). 86 | func (h *LeftistHeap) FindMin() heap.Item { 87 | if h.root == nil { 88 | return nil 89 | } 90 | return h.root.item 91 | } 92 | 93 | // Clear removes all items from the heap. 94 | func (h *LeftistHeap) Clear() { 95 | h.Init() 96 | } 97 | -------------------------------------------------------------------------------- /leftist/leftist_heap_test.go: -------------------------------------------------------------------------------- 1 | package leftist 2 | 3 | import ( 4 | "sort" 5 | "testing" 6 | 7 | "github.com/theodesp/go-heaps" 8 | ) 9 | 10 | func TestLeftistHeapInteger(t *testing.T) { 11 | heap := New().Init() 12 | 13 | numbers := []int{4, 3, 2, 5} 14 | 15 | for _, number := range numbers { 16 | heap.Insert(Int(number)) 17 | } 18 | 19 | sort.Ints(numbers) 20 | 21 | for _, number := range numbers { 22 | if Int(number) != heap.DeleteMin().(go_heaps.Integer) { 23 | t.Fail() 24 | } 25 | } 26 | } 27 | 28 | func TestLeftistHeapString(t *testing.T) { 29 | heap := &LeftistHeap{} 30 | 31 | strs := []string{"a", "ccc", "bb", "d"} 32 | 33 | for _, str := range strs { 34 | heap.Insert(Str(str)) 35 | } 36 | 37 | sort.Strings(strs) 38 | 39 | for _, str := range strs { 40 | if Str(str) != heap.DeleteMin().(go_heaps.String) { 41 | t.Fail() 42 | } 43 | } 44 | } 45 | 46 | func TestLeftistHeap(t *testing.T) { 47 | heap := &LeftistHeap{} 48 | 49 | numbers := []int{4, 3, -1, 5, 9} 50 | 51 | for _, number := range numbers { 52 | heap.Insert(Int(number)) 53 | } 54 | 55 | if heap.FindMin() != Int(-1) { 56 | t.Fail() 57 | } 58 | 59 | heap.Clear() 60 | if heap.FindMin() != nil { 61 | t.Fail() 62 | } 63 | } 64 | 65 | func Int(value int) go_heaps.Integer { 66 | return go_heaps.Integer(value) 67 | } 68 | 69 | func Str(value string) go_heaps.String { 70 | return go_heaps.String(value) 71 | } 72 | -------------------------------------------------------------------------------- /pairing/pairing_heap.go: -------------------------------------------------------------------------------- 1 | // Package pairing implements a Pairing heap Data structure 2 | // 3 | // Structure is not thread safe. 4 | // 5 | // Reference: https://en.wikipedia.org/wiki/Pairing_heap 6 | package pairing 7 | 8 | import ( 9 | heap "github.com/theodesp/go-heaps" 10 | "fmt" 11 | ) 12 | 13 | // PairHeap implements the Extended interface 14 | var _ heap.Extended = (*PairHeap)(nil) 15 | 16 | // PairHeap is an implementation of a Pairing Heap. 17 | // The zero value for PairHeap Root is an empty Heap. 18 | type PairHeap struct { 19 | root *node 20 | } 21 | 22 | // node contains the current item and the list if the sub-heaps 23 | type node struct { 24 | // for use by client; untouched by this library 25 | item heap.Item 26 | // List of children nodes all containing values less than the Top of the heap 27 | children []*node 28 | // A reference to the parent Heap Node 29 | parent *node 30 | } 31 | 32 | func (n *node) detach() []*node { 33 | if n.parent == nil { 34 | return nil // avoid detaching root 35 | } 36 | for _, node := range n.children { 37 | node.parent = nil 38 | } 39 | var idx int 40 | for i, node := range n.parent.children { 41 | if node == n { 42 | idx = i 43 | break 44 | } 45 | } 46 | n.parent.children = append(n.parent.children[:idx], n.parent.children[idx+1:]...) 47 | n.parent = nil 48 | return n.children 49 | } 50 | 51 | func (n *node) iterItem(iter heap.ItemIterator) { 52 | if !iter(n.item) { 53 | return 54 | } 55 | n.iterChildren(n.children, iter) 56 | } 57 | 58 | func (n *node) iterChildren(children []*node, iter heap.ItemIterator) { 59 | if len(children) == 0 { 60 | return 61 | } 62 | for _, node := range children { 63 | if !iter(node.item) { 64 | return 65 | } 66 | n.iterChildren(node.children, iter) 67 | } 68 | } 69 | 70 | func (n *node) findNode(item heap.Item) *node { 71 | if n.item.Compare(item) == 0 { 72 | return n 73 | } else { 74 | return n.findInChildren(n.children, item) 75 | } 76 | } 77 | 78 | func (n *node) findInChildren(children []*node, item heap.Item) *node { 79 | if len(children) == 0 { 80 | return nil 81 | } 82 | var node *node 83 | loop: 84 | for _, child := range children { 85 | node = child.findNode(item) 86 | if node != nil { 87 | break loop 88 | } 89 | } 90 | return node 91 | } 92 | 93 | // Init initializes or clears the PairHeap 94 | func (p *PairHeap) Init() *PairHeap { 95 | p.root = &node{} 96 | return p 97 | } 98 | 99 | // New returns an initialized PairHeap. 100 | func New() *PairHeap { return new(PairHeap).Init() } 101 | 102 | // IsEmpty returns true if PairHeap p is empty. 103 | // The complexity is O(1). 104 | func (p *PairHeap) IsEmpty() bool { 105 | return p.root.item == nil 106 | } 107 | 108 | // Resets the current PairHeap 109 | func (p *PairHeap) Clear() { 110 | p.Init() 111 | } 112 | 113 | // Find the smallest item in the priority queue. 114 | // The complexity is O(1). 115 | func (p *PairHeap) FindMin() heap.Item { 116 | if p.IsEmpty() { 117 | return nil 118 | } 119 | return p.root.item 120 | } 121 | 122 | // Inserts the value to the PairHeap and returns the item 123 | // The complexity is O(1). 124 | func (p *PairHeap) Insert(item heap.Item) heap.Item { 125 | p.root = merge(p.root, &node{item: item}) 126 | return item 127 | } 128 | 129 | 130 | // toDelete details what item to remove in a node call. 131 | type toDelete int 132 | 133 | const ( 134 | removeItem toDelete = iota // removes the given item 135 | removeMin // removes min item in the heap 136 | ) 137 | 138 | // DeleteMin removes the top most value from the PairHeap and returns it 139 | // The complexity is O(log n) amortized. 140 | func (p *PairHeap) DeleteMin() heap.Item { 141 | return p.deleteItem(nil, removeMin) 142 | } 143 | 144 | // Deletes a node from the heap and returns the item 145 | // The complexity is O(log n) amortized. 146 | func (p *PairHeap) Delete(item heap.Item) heap.Item { 147 | return p.deleteItem(item, removeItem) 148 | } 149 | 150 | func (p *PairHeap) deleteItem(item heap.Item, typ toDelete) heap.Item { 151 | var result node 152 | 153 | if len(p.root.children) == 0 { 154 | result = *p.root 155 | p.root.item = nil 156 | } else { 157 | switch typ { 158 | case removeMin: 159 | result = *p.root 160 | p.root = mergePairs(p.root, p.root.children) 161 | case removeItem: 162 | node := p.root.findNode(item) 163 | if node == nil { 164 | return nil 165 | } else { 166 | children := node.detach() 167 | p.root.children = append(p.root.children, children...) 168 | result = *node 169 | } 170 | default: 171 | panic("invalid type") 172 | } 173 | } 174 | 175 | return result.item 176 | } 177 | 178 | // Adjusts the value to the node item and returns it 179 | // The complexity is O(n) amortized. 180 | func (p *PairHeap) Adjust(item, new heap.Item) heap.Item { 181 | n := p.root.findNode(item) 182 | if n == nil { 183 | return nil 184 | } 185 | 186 | if n == p.root { 187 | p.DeleteMin() 188 | return p.Insert(new) 189 | } else { 190 | children := n.detach() 191 | p.Insert(new) 192 | p.root.children = append(p.root.children, children...) 193 | return n.item 194 | } 195 | } 196 | 197 | // Exhausting search of the element that matches item and returns it 198 | // The complexity is O(n) amortized. 199 | func (p *PairHeap) Find(item heap.Item) heap.Item { 200 | if p.IsEmpty() { 201 | return nil 202 | } 203 | var found heap.Item 204 | p.root.iterItem(func(i heap.Item) bool { 205 | if item.Compare(i) == 0 { 206 | found = i 207 | return false 208 | } else { 209 | return true 210 | } 211 | }) 212 | return found 213 | } 214 | 215 | 216 | // Do calls function cb on each element of the PairingHeap, in order of appearance. 217 | // The behavior of Do is undefined if cb changes *p. 218 | func (p *PairHeap) Do(it heap.ItemIterator) { 219 | if p.IsEmpty() { 220 | return 221 | } 222 | p.root.iterItem(it) 223 | } 224 | 225 | // Return the heap formed by taking the union of the item disjoint 226 | // current heap and a that is of the same type 227 | func (p *PairHeap) Meld(a heap.Interface) heap.Interface { 228 | if a == nil { 229 | return p 230 | } 231 | switch a.(type) { 232 | case *PairHeap: 233 | h := a.(*PairHeap) 234 | if h.IsEmpty() { 235 | return p 236 | } 237 | if p.IsEmpty() { 238 | p.root = h.root 239 | h.Clear() 240 | return p 241 | } 242 | if p.FindMin().Compare(h.FindMin()) > 0 { 243 | h.root = merge(h.root, p.root) 244 | p.root = h.root 245 | h.Clear() 246 | } else { 247 | p.root = merge(p.root, h.root) 248 | } 249 | 250 | default: 251 | panic(fmt.Sprintf("unexpected type %T", a)) 252 | } 253 | 254 | return p 255 | } 256 | 257 | func merge(a, b *node) *node { 258 | if a.item == nil { // Case when root is empty 259 | a = b 260 | return a 261 | } 262 | 263 | if a.item.Compare(b.item) < 0 { 264 | // put 'second' as the first child of 'first' and update the parent 265 | a.children = append([]*node{b}, a.children...) 266 | b.parent = a 267 | return a 268 | } else { 269 | // put 'first' as the first child of 'second' and update the parent 270 | b.children = append([]*node{a}, b.children...) 271 | a.parent = b 272 | return b 273 | } 274 | } 275 | 276 | // Merges heaps together 277 | func mergePairs(root *node, heaps []*node) *node { 278 | if len(heaps) == 1 { 279 | root = heaps[0] 280 | heaps[0].parent = nil 281 | return root 282 | } 283 | var merged *node 284 | for { // iteratively merge heaps 285 | if len(heaps) == 0 { 286 | break 287 | } 288 | if merged == nil { 289 | merged = merge(heaps[0], heaps[1]) 290 | heaps = heaps[2:] 291 | } else { 292 | merged = merge(merged, heaps[0]) 293 | heaps = heaps[1:] 294 | } 295 | } 296 | root = merged 297 | merged.parent = nil 298 | 299 | return root 300 | } 301 | -------------------------------------------------------------------------------- /pairing/pairing_heap_test.go: -------------------------------------------------------------------------------- 1 | package pairing 2 | 3 | import ( 4 | "testing" 5 | "github.com/stretchr/testify/suite" 6 | "github.com/stretchr/testify/assert" 7 | heap "github.com/theodesp/go-heaps" 8 | "fmt" 9 | "math/rand" 10 | "time" 11 | ) 12 | 13 | type PairingHeapTestSuite struct { 14 | suite.Suite 15 | heap *PairHeap 16 | } 17 | 18 | func (suite *PairingHeapTestSuite) SetupTest() { 19 | suite.heap = New() 20 | } 21 | 22 | func TestExampleTestSuite(t *testing.T) { 23 | suite.Run(t, new(PairingHeapTestSuite)) 24 | } 25 | 26 | func init() { 27 | seed := time.Now().Unix() 28 | fmt.Println(seed) 29 | rand.Seed(seed) 30 | } 31 | 32 | // perm returns a random permutation of n Int items in the range [0, n). 33 | func perm(n int) (out []heap.Item) { 34 | for _, v := range rand.Perm(n) { 35 | out = append(out, Int(v)) 36 | } 37 | return 38 | } 39 | 40 | // rang returns an ordered list of Int items in the range [0, n). 41 | func rang(n int) (out []heap.Item) { 42 | for i := 0; i < n; i++ { 43 | out = append(out, Int(i)) 44 | } 45 | return 46 | } 47 | 48 | // all extracts all items from a tree in order as a slice. 49 | func all(t *PairHeap) (out []heap.Item) { 50 | t.Do(func(a heap.Item) bool { 51 | out = append(out, a) 52 | return true 53 | }) 54 | return 55 | } 56 | 57 | // rangerev returns a reversed ordered list of Int items in the range [0, n). 58 | func rangrev(n int) (out []heap.Item) { 59 | for i := n - 1; i >= 0; i-- { 60 | out = append(out, Int(i)) 61 | } 62 | return 63 | } 64 | 65 | func testMinHeapInvariance(suite *PairingHeapTestSuite) { 66 | suite.T().Helper() 67 | var items []heap.Item 68 | for { 69 | item := suite.heap.DeleteMin() 70 | if item == nil { 71 | break 72 | } else { 73 | items = append(items, item) 74 | } 75 | } 76 | 77 | for i := 0; i < len(items)-1; i += 1 { 78 | assert.True(suite.T(), items[i].Compare(items[i+1]) < 0) 79 | } 80 | } 81 | 82 | func (suite *PairingHeapTestSuite) TestIsEmpty() { 83 | assert.Equal(suite.T(), suite.heap.IsEmpty(), true) 84 | suite.heap.Insert(Int(4)) 85 | suite.heap.Insert(Int(2)) 86 | suite.heap.Insert(Int(1)) 87 | 88 | assert.Equal(suite.T(), suite.heap.IsEmpty(), false) 89 | } 90 | 91 | func (suite *PairingHeapTestSuite) TestMeld() { 92 | assert.NotNil(suite.T(), suite.heap.Meld(nil)) 93 | 94 | heapB := New() 95 | heapB.Insert(Int(4)) 96 | heapB.Insert(Int(2)) 97 | heapB.Insert(Int(6)) 98 | heapB.Insert(Int(7)) 99 | 100 | suite.heap.Meld(heapB) 101 | testMinHeapInvariance(suite) 102 | 103 | suite.heap.Insert(Int(4)) 104 | suite.heap.Insert(Int(6)) 105 | suite.heap.Insert(Int(2)) 106 | suite.heap.Insert(Int(10)) 107 | 108 | heapB = New() 109 | heapB.Insert(Int(1)) 110 | heapB.Insert(Int(3)) 111 | heapB.Insert(Int(5)) 112 | heapB.Insert(Int(7)) 113 | 114 | suite.heap.Meld(heapB) 115 | testMinHeapInvariance(suite) 116 | } 117 | 118 | func (suite *PairingHeapTestSuite) TestFindMin() { 119 | suite.heap.Insert(Int(4)) 120 | suite.heap.Insert(Int(2)) 121 | suite.heap.Insert(Int(6)) 122 | suite.heap.Insert(Int(3)) 123 | 124 | assert.Equal(suite.T(), suite.heap.FindMin(), Int(2)) 125 | testMinHeapInvariance(suite) 126 | } 127 | 128 | func (suite *PairingHeapTestSuite) TestDeleteMin() { 129 | for _, v := range perm(100) { 130 | suite.heap.Insert(v) 131 | } 132 | var got []heap.Item 133 | for v := suite.heap.DeleteMin(); v != nil; v = suite.heap.DeleteMin() { 134 | got = append(got, v) 135 | } 136 | assert.ElementsMatch(suite.T(), got, rang(100)) 137 | } 138 | 139 | func (suite *PairingHeapTestSuite) TestInsert() { 140 | for _, item := range perm(100) { 141 | suite.heap.Insert(item) 142 | } 143 | min := suite.heap.FindMin() 144 | assert.Equal(suite.T(), min, Int(0)) 145 | 146 | got := all(suite.heap) 147 | want := rang(100) 148 | assert.ElementsMatch(suite.T(), got, want) 149 | testMinHeapInvariance(suite) 150 | } 151 | 152 | func (suite *PairingHeapTestSuite) TestFind() { 153 | item := suite.heap.Find(Int(10)) 154 | assert.Nil(suite.T(), item) 155 | 156 | suite.heap.Insert(Int(4)) 157 | 158 | item = suite.heap.Find(Int(4)) 159 | assert.NotNil(suite.T(),item) 160 | assert.Equal(suite.T(),item, Int(4)) 161 | 162 | suite.heap.Insert(Int(8)) 163 | suite.heap.Insert(Int(2)) 164 | suite.heap.Insert(Int(5)) 165 | suite.heap.Insert(Int(3)) 166 | suite.heap.Insert(Int(9)) 167 | 168 | item = suite.heap.Find(Int(9)) 169 | assert.NotNil(suite.T(),item) 170 | assert.Equal(suite.T(),item, Int(9)) 171 | testMinHeapInvariance(suite) 172 | } 173 | 174 | func (suite *PairingHeapTestSuite) TestAdjust() { 175 | for _, v := range rang(10) { 176 | suite.heap.Insert(v) 177 | } 178 | for i, item := range rangrev(10) { 179 | assert.NotNil(suite.T(), suite.heap.Adjust(item, Int(i))) 180 | } 181 | testMinHeapInvariance(suite) 182 | } 183 | 184 | func (suite *PairingHeapTestSuite) TestDelete() { 185 | for _, v := range rang(10) { 186 | suite.heap.Insert(v) 187 | } 188 | for _, item := range rangrev(10) { 189 | assert.NotNil(suite.T(), suite.heap.Delete(item)) 190 | } 191 | 192 | assert.Nil(suite.T(), suite.heap.DeleteMin()) 193 | } 194 | 195 | func Int(value int) heap.Integer { 196 | return heap.Integer(value) 197 | } -------------------------------------------------------------------------------- /rank_pairing/rank_pairing_heap.go: -------------------------------------------------------------------------------- 1 | package rank_paring 2 | 3 | import ( 4 | "fmt" 5 | 6 | heap "github.com/theodesp/go-heaps" 7 | ) 8 | 9 | type node struct { 10 | item heap.Item 11 | left, next, parent *node 12 | rank int 13 | } 14 | 15 | // RPHeap is an implementation of a rank Pairing Heap. 16 | // The zero value for RPHeap Root is an empty Heap. 17 | type RPHeap struct { 18 | head *node 19 | size int 20 | } 21 | 22 | type nInf struct{} 23 | 24 | func (a nInf) Compare(b heap.Item) int { 25 | switch b.(type) { 26 | case nInf: 27 | return 0 28 | default: 29 | return -1 30 | } 31 | } 32 | 33 | // wrap compare function to support nInf (negative inf) type 34 | func compare(a, b heap.Item) int { 35 | switch b.(type) { 36 | case nInf: 37 | switch a.(type) { 38 | case nInf: 39 | return 0 40 | default: 41 | return 1 42 | } 43 | default: 44 | return a.Compare(b) 45 | } 46 | } 47 | 48 | // Init initializes or clears the rankPairingHeap 49 | func (p *RPHeap) Init() *RPHeap { 50 | p.head = &node{} 51 | p.size = 0 52 | return p 53 | } 54 | 55 | // New returns an initialized rankPairingHeap. 56 | func New() *RPHeap { return new(RPHeap).Init() } 57 | 58 | // FindMin returns the value of root 59 | // Complexity: O(1) 60 | func (r *RPHeap) FindMin() heap.Item { 61 | return r.head.item 62 | } 63 | 64 | // Insert the value val into the heap and return it 65 | // Complexity: O(1) 66 | func (r *RPHeap) Insert(val heap.Item) heap.Item { 67 | ptr := &node{ 68 | item: val, 69 | } 70 | r.insertRoot(ptr) 71 | r.size++ 72 | return val 73 | } 74 | 75 | // DeleteMin removes the top most value from the rankPairingHeap and returns it 76 | // Complexity: O(log n) 77 | func (r *RPHeap) DeleteMin() heap.Item { 78 | bucket := make([]*node, r.maxBucketSize()) 79 | ret := r.head.item 80 | // an empty heap will panic here 81 | if ret == nil { 82 | return nil 83 | } 84 | r.size-- 85 | for ptr := r.head.left; ptr != nil; { 86 | nextPtr := ptr.next 87 | ptr.next = nil 88 | ptr.parent = nil 89 | bucket = multiPass(bucket, ptr) 90 | ptr = nextPtr 91 | } 92 | for ptr := r.head.next; ptr != r.head; { 93 | nextPtr := ptr.next 94 | ptr.next = nil 95 | bucket = multiPass(bucket, ptr) 96 | ptr = nextPtr 97 | } 98 | r.head = &node{} 99 | for _, ptr := range bucket { 100 | if ptr != nil { 101 | r.insertRoot(ptr) 102 | } 103 | } 104 | return ret 105 | } 106 | 107 | // Clear the whole rankPairingHeap 108 | func (r *RPHeap) Clear() { 109 | r.Init() 110 | } 111 | 112 | // Merge a rankPairingHeap r0 into a heap r, then clear r0 113 | // Complexity: O(1) 114 | func (r *RPHeap) Meld(a heap.Interface) heap.Interface { 115 | switch a.(type) { 116 | case *RPHeap: 117 | default: 118 | panic(fmt.Sprintf("unexpected type %T", a)) 119 | } 120 | r0 := a.(*RPHeap) 121 | if r.head.item == nil { 122 | r.head = r0.head 123 | r.size = r0.size 124 | r0.Clear() 125 | return r 126 | } 127 | if r0.head.item == nil { 128 | return r 129 | } 130 | if compare(r.head.item, r0.head.item) < 0 { 131 | mergeRes := merge(r, r0) 132 | r0.Clear() 133 | return mergeRes 134 | } else { 135 | mergeRes := merge(r0, r) 136 | r0.Clear() 137 | return mergeRes 138 | } 139 | } 140 | 141 | // Size returns the size of the RPHeap 142 | func (r *RPHeap) Size() int { 143 | return r.size 144 | } 145 | 146 | // Adjust the value of an item, since we have to find the item 147 | // Complexity is O(n) 148 | func (r *RPHeap) Adjust(old, new heap.Item) heap.Item { 149 | ptr := r.find(r.head, old) 150 | if ptr == nil { 151 | return nil 152 | } 153 | if compare(ptr.item, new) < 0 { 154 | r.decrease(ptr, nInf{}) 155 | r.DeleteMin() 156 | r.Insert(new) 157 | } else { 158 | r.decrease(ptr, new) 159 | } 160 | return new 161 | } 162 | 163 | // Delete an item from the heap 164 | // Complexity is O(n) 165 | func (r *RPHeap) Delete(val heap.Item) heap.Item { 166 | ptr := r.find(r.head, val) 167 | if ptr == nil { 168 | return nil 169 | } 170 | if ptr == r.head { 171 | return r.DeleteMin() 172 | } 173 | r.decrease(ptr, nInf{}) 174 | r.DeleteMin() 175 | return val 176 | } 177 | 178 | // Decrease the value of an item 179 | // Complexity is O(log n) 180 | func (r *RPHeap) decrease(ptr *node, val heap.Item) { 181 | if compare(val, ptr.item) < 0 { 182 | ptr.item = val 183 | } 184 | if ptr == r.head { 185 | return 186 | } 187 | if ptr.parent == nil { 188 | if compare(ptr.item, r.head.item) < 0 { 189 | r.head = ptr 190 | } 191 | } else { 192 | parent := ptr.parent 193 | if ptr == parent.left { 194 | parent.left = ptr.next 195 | if parent.left != nil { 196 | parent.left.parent = parent 197 | } 198 | } else { 199 | parent.next = ptr.next 200 | if parent.next != nil { 201 | parent.next.parent = parent 202 | } 203 | } 204 | ptr.next, ptr.parent = nil, nil 205 | if ptr.left != nil { 206 | ptr.rank = ptr.left.rank + 1 207 | } else { 208 | ptr.rank = 0 209 | } 210 | r.insertRoot(ptr) 211 | if parent.parent == nil { 212 | parent.rank = getrank(parent.left) + 1 213 | } else { 214 | for parent.parent != nil { 215 | leftrank := getrank(parent.left) 216 | nextrank := getrank(parent.next) 217 | newrank := leftrank + 1 218 | if leftrank != nextrank { 219 | if leftrank > nextrank { 220 | newrank = leftrank 221 | } else { 222 | newrank = nextrank 223 | } 224 | } 225 | if newrank >= parent.rank { 226 | break 227 | } 228 | parent.rank = newrank 229 | parent = parent.parent 230 | } 231 | } 232 | } 233 | } 234 | 235 | // Find the pointer to an item 236 | // Complexity: O(n) 237 | func (r *RPHeap) find(root *node, val heap.Item) *node { 238 | if root == nil { 239 | return nil 240 | } else if compare(root.item, val) == 0 { 241 | return root 242 | } else { 243 | if leftfind := r.find(root.left, val); leftfind != nil { 244 | return leftfind 245 | } 246 | for ptr := root.next; ptr != nil && ptr != root; ptr = ptr.next { 247 | if compare(ptr.item, val) == 0 { 248 | return ptr 249 | } 250 | if leftfind := r.find(ptr.left, val); leftfind != nil { 251 | return leftfind 252 | } 253 | } 254 | } 255 | return nil 256 | } 257 | 258 | func getrank(root *node) int { 259 | if root == nil { 260 | return -1 261 | } 262 | return root.rank 263 | } 264 | 265 | func merge(r0, r1 *RPHeap) *RPHeap { 266 | if r1.Size() == 1 { 267 | ptr := r1.head 268 | ptr.next, ptr.parent, ptr.left, ptr.rank = nil, nil, nil, 0 269 | r0.insertRoot(ptr) 270 | r0.size++ 271 | return &RPHeap{ 272 | head: r0.head, 273 | size: r0.size, 274 | } 275 | } else if r0.Size() == 1 { 276 | return merge(r1, r0) 277 | } 278 | r0.head.next, r1.head.next = r1.head.next, r0.head.next 279 | r0.size += r1.size 280 | return &RPHeap{ 281 | head: r0.head, 282 | size: r0.size, 283 | } 284 | } 285 | 286 | func (r *RPHeap) maxBucketSize() int { 287 | bit, cnt := 1, r.size 288 | for cnt > 1 { 289 | cnt /= 2 290 | bit++ 291 | } 292 | return bit + 1 293 | } 294 | 295 | func (r *RPHeap) insertRoot(ptr *node) { 296 | if r.head.item == nil { 297 | r.head = ptr 298 | ptr.next = ptr 299 | } else { 300 | ptr.next = r.head.next 301 | r.head.next = ptr 302 | if compare(ptr.item, r.head.item) < 0 { 303 | r.head = ptr 304 | } 305 | } 306 | } 307 | 308 | func multiPass(bucket []*node, ptr *node) []*node { 309 | for bucket[ptr.rank] != nil { 310 | rank := ptr.rank 311 | ptr = link(ptr, bucket[rank]) 312 | bucket[rank] = nil 313 | } 314 | bucket[ptr.rank] = ptr 315 | return bucket 316 | } 317 | 318 | func link(left *node, right *node) *node { 319 | if right == nil { 320 | return left 321 | } 322 | var winner, loser *node 323 | if compare(right.item, left.item) < 0 { 324 | winner = right 325 | loser = left 326 | } else { 327 | winner = left 328 | loser = right 329 | } 330 | loser.parent = winner 331 | if winner.left != nil { 332 | loser.next = winner.left 333 | loser.next.parent = loser 334 | } 335 | winner.left = loser 336 | winner.rank = loser.rank + 1 337 | return winner 338 | } 339 | -------------------------------------------------------------------------------- /rank_pairing/rank_pairing_heap_test.go: -------------------------------------------------------------------------------- 1 | package rank_paring 2 | 3 | import ( 4 | "sort" 5 | "testing" 6 | 7 | heap "github.com/theodesp/go-heaps" 8 | ) 9 | 10 | func TestRPHeapInteger(t *testing.T) { 11 | rpheap := New() 12 | numbers := []int{4, 3, 2, 5} 13 | for _, number := range numbers { 14 | rpheap.Insert(Int(number)) 15 | } 16 | sort.Ints(numbers) 17 | for _, number := range numbers { 18 | if Int(number) != rpheap.DeleteMin().(heap.Integer) { 19 | t.Fail() 20 | } 21 | } 22 | if rpheap.DeleteMin() != nil { 23 | t.Fail() 24 | } 25 | if rpheap.FindMin() != nil { 26 | t.Fail() 27 | } 28 | } 29 | 30 | func TestRPHeapAdjustDecrease(t *testing.T) { 31 | rpheap := New() 32 | numbers := []int{4, 3, 2, 5} 33 | for _, number := range numbers { 34 | rpheap.Insert(Int(number)) 35 | } 36 | ans := []int{1, 2, 3, 5} 37 | rpheap.Adjust(Int(4), Int(1)) 38 | for _, number := range ans { 39 | if Int(number) != rpheap.DeleteMin().(heap.Integer) { 40 | t.Fail() 41 | } 42 | } 43 | } 44 | 45 | func TestRPHeapAdjustDecrease2(t *testing.T) { 46 | rpheap := New() 47 | numbers := []int{9, 2, 4, 3, 1, 5, 6, 8, 7, 0} 48 | for _, number := range numbers { 49 | rpheap.Insert(Int(number)) 50 | } 51 | rpheap.DeleteMin() 52 | ans := []int{0, 1, 2, 3, 5, 6, 7, 8, 9} 53 | rpheap.Adjust(Int(4), Int(0)) 54 | for _, number := range ans { 55 | if res := rpheap.DeleteMin().(heap.Integer); Int(number) != res { 56 | t.Fail() 57 | } 58 | } 59 | } 60 | 61 | func TestRPHeapAdjustNotExist(t *testing.T) { 62 | rpheap := New() 63 | numbers := []int{4, 3, 2, 5} 64 | for _, number := range numbers { 65 | rpheap.Insert(Int(number)) 66 | } 67 | ans := []int{2, 3, 4, 5} 68 | rpheap.Adjust(Int(6), Int(1)) 69 | for _, number := range ans { 70 | if Int(number) != rpheap.DeleteMin().(heap.Integer) { 71 | t.Fail() 72 | } 73 | } 74 | } 75 | 76 | func TestRPHeapAdjustIncrease(t *testing.T) { 77 | rpheap := New() 78 | numbers := []int{4, 3, 2, 5} 79 | for _, number := range numbers { 80 | rpheap.Insert(Int(number)) 81 | } 82 | ans := []int{2, 3, 5, 6} 83 | rpheap.Adjust(Int(4), Int(6)) 84 | for _, number := range ans { 85 | if Int(number) != rpheap.DeleteMin().(heap.Integer) { 86 | t.Fail() 87 | } 88 | } 89 | } 90 | 91 | func TestRPHeapDelete(t *testing.T) { 92 | rpheap := New() 93 | numbers := []int{4, 3, 2, 5} 94 | for _, number := range numbers { 95 | rpheap.Insert(Int(number)) 96 | } 97 | ans := []int{2, 3, 5} 98 | rpheap.Delete(Int(4)) 99 | for _, number := range ans { 100 | if Int(number) != rpheap.DeleteMin().(heap.Integer) { 101 | t.Fail() 102 | } 103 | } 104 | } 105 | 106 | func TestRPHeapString(t *testing.T) { 107 | rpheap := New() 108 | 109 | strs := []string{"a", "ccc", "bb", "d"} 110 | 111 | for _, str := range strs { 112 | rpheap.Insert(Str(str)) 113 | } 114 | 115 | sort.Strings(strs) 116 | 117 | for _, str := range strs { 118 | if Str(str) != rpheap.DeleteMin().(heap.String) { 119 | t.Fail() 120 | } 121 | } 122 | } 123 | 124 | func TestRPHeapInteger2(t *testing.T) { 125 | rpheap := New() 126 | rpheap.Insert(Int(5)) 127 | rpheap.Insert(Int(3)) 128 | if rpheap.DeleteMin().(heap.Integer) != Int(3) { 129 | t.Fail() 130 | } 131 | rpheap.Insert(Int(4)) 132 | rpheap.Insert(Int(2)) 133 | if rpheap.DeleteMin().(heap.Integer) != Int(2) { 134 | t.Fail() 135 | } 136 | if rpheap.DeleteMin().(heap.Integer) != Int(4) { 137 | t.Fail() 138 | } 139 | if rpheap.DeleteMin().(heap.Integer) != Int(5) { 140 | t.Fail() 141 | } 142 | } 143 | 144 | func TestRPHeapMerge(t *testing.T) { 145 | runTestMerge([]int{2, 8, 5, 7}, []int{4, 9, 6}, t) 146 | runTestMerge([]int{4, 9, 6}, []int{2, 8, 5, 7}, t) 147 | runTestMerge([]int{2}, []int{4, 9, 6}, t) 148 | runTestMerge([]int{2, 8, 5, 7}, []int{4}, t) 149 | runTestMerge([]int{2, 8, 5, 7}, []int{}, t) 150 | runTestMerge([]int{}, []int{4, 9, 6}, t) 151 | } 152 | 153 | func runTestMerge(arr1, arr2 []int, t *testing.T) { 154 | ans := append(arr1, arr2...) 155 | sort.Ints(ans) 156 | rpheap1 := New() 157 | rpheap2 := New() 158 | for _, number := range arr1 { 159 | rpheap1.Insert(Int(number)) 160 | } 161 | for _, number := range arr2 { 162 | rpheap2.Insert(Int(number)) 163 | } 164 | rpheap1 = rpheap1.Meld(rpheap2).(*RPHeap) 165 | for _, number := range ans { 166 | if Int(number) != rpheap1.DeleteMin().(heap.Integer) { 167 | t.Fail() 168 | } 169 | } 170 | if rpheap2.Size() != 0 { 171 | t.Error("rpheap2 is not empty") 172 | t.Fail() 173 | } 174 | if rpheap1.Size() != 0 { 175 | t.Error("rpheap1 is not empty: size =", rpheap1.Size()) 176 | t.Fail() 177 | } 178 | } 179 | 180 | func Int(value int) heap.Integer { 181 | return heap.Integer(value) 182 | } 183 | 184 | func Str(value string) heap.String { 185 | return heap.String(value) 186 | } 187 | -------------------------------------------------------------------------------- /skew/skew_heap.go: -------------------------------------------------------------------------------- 1 | // Package skew implements a Skew heap Data structure 2 | // 3 | // Structure is not thread safe. 4 | // 5 | // Reference: https://en.wikipedia.org/wiki/Skew_heap 6 | package skew 7 | 8 | import ( 9 | heap "github.com/theodesp/go-heaps" 10 | ) 11 | 12 | // Node is a leaf in the heap. 13 | type node struct { 14 | item heap.Item 15 | right, left *node 16 | } 17 | 18 | func merge(x, y *node) *node { 19 | if x == nil { 20 | return y 21 | } 22 | 23 | if y == nil { 24 | return x 25 | } 26 | // x should point to the smaller item 27 | if x.item.Compare(y.item) > 0 { 28 | x, y = y, x 29 | } 30 | 31 | x.left, x.right = x.right, x.left 32 | x.left = merge(y, x.left) 33 | 34 | return x 35 | } 36 | 37 | // SkewHeap is a skew heap implementation. 38 | type SkewHeap struct { 39 | root *node 40 | } 41 | 42 | // Init initializes or clears the SkewHeap 43 | func (h *SkewHeap) Init() *SkewHeap { 44 | h.root = &node{} 45 | return h 46 | } 47 | 48 | // New returns an initialized SkewHeap. 49 | func New() *SkewHeap { return new(SkewHeap).Init() } 50 | 51 | // Insert adds an item into the heap. 52 | func (h *SkewHeap) Insert(v heap.Item) heap.Item { 53 | h.root = merge(&node{ 54 | item: v, 55 | }, h.root) 56 | 57 | return v 58 | } 59 | 60 | // DeleteMin deletes the minimum value and returns it. 61 | func (h *SkewHeap) DeleteMin() heap.Item { 62 | v := h.root 63 | 64 | h.root = merge(v.right, v.left) 65 | 66 | return v.item 67 | } 68 | 69 | // FindMin finds the minimum value. 70 | func (h *SkewHeap) FindMin() heap.Item { 71 | return h.root.item 72 | } 73 | 74 | // Clear removes all items from the heap. 75 | func (h *SkewHeap) Clear() { 76 | h.Init() 77 | } 78 | -------------------------------------------------------------------------------- /skew/skew_heap_test.go: -------------------------------------------------------------------------------- 1 | // Package pairing implements a Pairing heap Data structure 2 | // 3 | // Structure is not thread safe. 4 | // 5 | // Reference: https://en.wikipedia.org/wiki/Pairing_heap 6 | package skew 7 | 8 | import ( 9 | "sort" 10 | "testing" 11 | 12 | heap "github.com/theodesp/go-heaps" 13 | ) 14 | 15 | func TestSkewHeapInteger(t *testing.T) { 16 | skew := &SkewHeap{} 17 | 18 | numbers := []int{4, 3, 2, 5} 19 | 20 | for _, number := range numbers { 21 | skew.Insert(Int(number)) 22 | } 23 | 24 | sort.Ints(numbers) 25 | 26 | for _, number := range numbers { 27 | if Int(number) != skew.DeleteMin().(heap.Integer) { 28 | t.Fail() 29 | } 30 | } 31 | } 32 | 33 | func TestSkewHeapString(t *testing.T) { 34 | skew := &SkewHeap{} 35 | 36 | strs := []string{"a", "ccc", "bb", "d"} 37 | 38 | for _, str := range strs { 39 | skew.Insert(Str(str)) 40 | } 41 | 42 | sort.Strings(strs) 43 | 44 | for _, str := range strs { 45 | if Str(str) != skew.DeleteMin().(heap.String) { 46 | t.Fail() 47 | } 48 | } 49 | } 50 | 51 | func TestSkewHeap(t *testing.T) { 52 | skew := &SkewHeap{} 53 | 54 | numbers := []int{4, 3, -1, 5, 9} 55 | 56 | for _, number := range numbers { 57 | skew.Insert(Int(number)) 58 | } 59 | 60 | if skew.FindMin() != Int(-1) { 61 | t.Fail() 62 | } 63 | 64 | skew.Clear() 65 | if skew.FindMin() != nil { 66 | t.Fail() 67 | } 68 | } 69 | 70 | func Int(value int) heap.Integer { 71 | return heap.Integer(value) 72 | } 73 | 74 | func Str(value string) heap.String { 75 | return heap.String(value) 76 | } 77 | -------------------------------------------------------------------------------- /treap/treap.go: -------------------------------------------------------------------------------- 1 | // Package treap implements a treap (tree-heap) data structure 2 | // Each node hold a key and a random priority 3 | // Keys arranged as binary search tree (BST) 4 | // Priorities arranged as heap 5 | // 6 | // Structure is not thread safe. 7 | // 8 | // Reference: https://en.wikipedia.org/wiki/Treap 9 | 10 | package treap 11 | 12 | import ( 13 | "math/rand" 14 | "time" 15 | 16 | goheap "github.com/theodesp/go-heaps" 17 | ) 18 | 19 | const MaxInt = int(^uint(0) >> 1) 20 | 21 | type Node struct { 22 | Priority goheap.Integer 23 | Key goheap.Item 24 | Left, Right *Node 25 | } 26 | 27 | // Split treap into 2 treaps: 28 | // - All key in left treap <= key 29 | // - All key in right treap > key 30 | func split(t *Node, key goheap.Item) (*Node, *Node) { 31 | var ( 32 | left, right *Node 33 | ) 34 | 35 | if t == nil { 36 | return nil, nil 37 | } else if t.Key.Compare(key) <= 0 { 38 | t.Right, right = split(t.Right, key) 39 | left := t 40 | return left, right 41 | } else { 42 | left, t.Left = split(t.Left, key) 43 | right := t 44 | return left, right 45 | } 46 | } 47 | 48 | // Merge 2 treaps into one with condition: 49 | // max key on left treap is <= than min key on right treap 50 | func merge(x, y *Node) *Node { 51 | if x == nil { 52 | return y 53 | } 54 | 55 | if y == nil { 56 | return x 57 | } 58 | 59 | if x.Priority.Compare(y.Priority) > 0 { 60 | x.Right = merge(x.Right, y) 61 | return x 62 | } else { 63 | y.Left = merge(x, y.Left) 64 | return y 65 | } 66 | } 67 | 68 | func (t *Node) insert(pnode *Node) *Node { 69 | if t == nil { 70 | return pnode 71 | } 72 | 73 | if pnode.Priority.Compare(t.Priority) > 0 { 74 | pnode.Left, pnode.Right = split(t, pnode.Key) 75 | return pnode 76 | } 77 | 78 | if t.Key.Compare(pnode.Key) != 1 { 79 | t.Right = t.Right.insert(pnode) 80 | } else { 81 | t.Left = t.Left.insert(pnode) 82 | } 83 | return t 84 | } 85 | 86 | // Generate priority for new node. 87 | func generatePriority() goheap.Integer { 88 | return goheap.Integer(rand.Intn(MaxInt)) 89 | } 90 | 91 | // Treap implementation. 92 | type Treap struct { 93 | Root *Node 94 | } 95 | 96 | // Init initializes or clears the Treap 97 | func (h *Treap) Init() *Treap { 98 | rand.Seed(time.Now().UnixNano()) 99 | return &Treap{} 100 | } 101 | 102 | // New returns an initialized Treap. 103 | func New() *Treap { return new(Treap).Init() } 104 | 105 | // Insert adds an item into the heap. 106 | func (h *Treap) Insert(v goheap.Item) goheap.Item { 107 | pnode := &Node{ 108 | Priority: generatePriority(), 109 | Key: v, 110 | } 111 | 112 | if h.Root == nil { 113 | h.Root = pnode 114 | } else { 115 | h.Root = h.Root.insert(pnode) 116 | } 117 | return v 118 | } 119 | 120 | // DeleteMin deletes the minimum value and returns it. 121 | func (h *Treap) DeleteMin() goheap.Item { 122 | v := h.Root 123 | if v == nil { 124 | return nil 125 | } 126 | 127 | if v.Left == nil { 128 | h.Root = v.Right 129 | return v.Key 130 | } 131 | 132 | for ; v.Left.Left != nil; v = v.Left { 133 | } 134 | 135 | min := v.Left 136 | v.Left = merge(v.Left.Left, v.Left.Right) 137 | return min.Key 138 | } 139 | 140 | // FindMin finds the minimum value. 141 | func (h *Treap) FindMin() goheap.Item { 142 | v := h.Root 143 | if v == nil { 144 | return nil 145 | } 146 | 147 | for ; v.Left != nil; v = v.Left { 148 | } 149 | 150 | return v.Key 151 | } 152 | 153 | // Clear removes all items from the heap. 154 | func (h *Treap) Clear() { 155 | h.Root = nil 156 | } 157 | -------------------------------------------------------------------------------- /treap/treap_test.go: -------------------------------------------------------------------------------- 1 | package treap 2 | 3 | import ( 4 | "sort" 5 | "testing" 6 | 7 | goheap "github.com/theodesp/go-heaps" 8 | ) 9 | 10 | func TestTreapInteger(t *testing.T) { 11 | treap := New() 12 | 13 | numbers := []int{4, 3, 2, 5} 14 | 15 | for _, number := range numbers { 16 | treap.Insert(goheap.Integer(number)) 17 | } 18 | 19 | sort.Ints(numbers) 20 | 21 | for _, number := range numbers { 22 | if goheap.Integer(number) != treap.DeleteMin().(goheap.Integer) { 23 | t.Fail() 24 | } 25 | } 26 | } 27 | 28 | func TestTreapString(t *testing.T) { 29 | treap := New() 30 | 31 | strs := []string{"a", "ccc", "bb", "d"} 32 | 33 | for _, str := range strs { 34 | treap.Insert(goheap.String(str)) 35 | } 36 | 37 | sort.Strings(strs) 38 | 39 | for _, str := range strs { 40 | if goheap.String(str) != treap.DeleteMin().(goheap.String) { 41 | t.Fail() 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /version.go: -------------------------------------------------------------------------------- 1 | package go_heaps 2 | 3 | // Version The main version number that is being run at the moment. 4 | const Version = "0.0.1" --------------------------------------------------------------------------------