├── .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 | [](#contributors)
3 | ---
4 |
5 |
6 |
7 |
8 |
9 |
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 |
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"
--------------------------------------------------------------------------------