├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── bloom ├── bloom.go └── bloom_test.go ├── datastructure ├── binary-tree.go ├── binary-tree_test.go ├── graph.go ├── graph_test.go ├── priority-queue.go ├── priority-queue_test.go ├── queue.go ├── queue_test.go ├── stack.go └── stack_test.go ├── graph ├── bellman-ford.go ├── bellman-ford_test.go ├── breadth-first-search.go ├── depth-first-search.go ├── dijkstra.go ├── dijkstra_test.go └── search_test.go ├── search ├── benchmark_test.go ├── binary-tree.go ├── binary.go ├── hash.go ├── search_test.go └── sequential.go └── sort ├── README.md ├── benchmark_test.go ├── bubble.go ├── bucket.go ├── bucket_test.go ├── counting.go ├── counting_test.go ├── doc └── sort-random-1K.png ├── heap.go ├── insert.go ├── merge.go ├── quick.go ├── quick_test.go ├── selection.go ├── shell.go └── sort_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.test 2 | *.prof 3 | current -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.7.3 4 | - tip 5 | 6 | os: 7 | - linux 8 | 9 | sudo: false 10 | 11 | install: 12 | - echo "skipping travis' default" 13 | 14 | script: 15 | - go test -v ./... 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Taichi Nakashima 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-algorithms [![Build Status](http://img.shields.io/travis/tcnksm/go-algorithms.svg?style=flat-square)][travis] 2 | 3 | [travis]: https://travis-ci.org/tcnksm/go-algorithms 4 | 5 | Golang implementation of different algorithms and data structure. This is just for fun and learning. Don't use this for your project. 6 | 7 | ## References 8 | 9 | - https://github.com/arnauddri/algorithms 10 | - https://github.com/0xAX/go-algorithms 11 | -------------------------------------------------------------------------------- /bloom/bloom.go: -------------------------------------------------------------------------------- 1 | package bloom 2 | 3 | import ( 4 | "hash" 5 | "hash/fnv" 6 | "math" 7 | ) 8 | 9 | // BloomFilter 10 | // https://en.wikipedia.org/wiki/Bloom_filter 11 | type BloomFilter struct { 12 | h hash.Hash32 13 | 14 | k int // k is number of hash functions 15 | m int64 // m is filter size in bits 16 | 17 | bucket int64 18 | states []uint32 19 | } 20 | 21 | // New creates a new Bloom Filter. n is number of elements 22 | // you want to store and p is false-positive probability. 23 | // 24 | // When you store data on m bits array, the probability of 25 | // collision is 1/m, so not-collision is 1 - (1/m). 26 | // 27 | // When you use k hash functions and store n elements, 28 | // the probalibity of not collision is: 29 | // 30 | // (1 - (1/m))^(k*n) 31 | // 32 | // In this case, when you inject non-mebers elements, 33 | // the probalitity of all bit becames 1 is: 34 | // 35 | // (1 - (1 - (1/m))^(k*n) )^k = (1 - e^(-kn/m))^k 36 | // 37 | // For a given m and n, the value of the number of hash functions 38 | // k that minimizes the false positive probability is, 39 | // 40 | // k = (m/n)ln(2) 41 | // 42 | // The required number of bits m, the number of inserted elements 43 | // and a desired false positive probability p (and assuming the optimal 44 | // value of k is used) can be) 45 | // 46 | // m = n * log2(e) * log2(1/p) 47 | // 48 | func New(n, p int) *BloomFilter { 49 | // TODO(tcnksm): error handling 50 | m := int64(math.Abs(math.Ceil(float64(n) * math.Log2(math.E) * math.Log2(1/float64(p))))) 51 | k := int(float64(m/int64(n)) * math.Log2(2)) 52 | return newFilter(k, m) 53 | } 54 | 55 | // New creates Bloom Filter with m bits and k hashing functions. 56 | func newFilter(k int, m int64) *BloomFilter { 57 | bucket := m / 32 58 | return &BloomFilter{ 59 | h: fnv.New32a(), 60 | k: k, 61 | m: m, 62 | bucket: bucket, 63 | states: make([]uint32, uint(bucket)), 64 | } 65 | } 66 | 67 | // Add adds data to the filter. 68 | func (f *BloomFilter) Add(data []byte) error { 69 | for i := 1; i < (f.k + 1); i++ { 70 | f.h.Write(data) 71 | v := f.h.Sum32() 72 | f.h.Reset() 73 | 74 | index := int64(v*uint32(i)) % f.m // [0,m] 75 | bucket := (index / 32) % f.bucket // [0,bucket] 76 | offset := index % 32 // [0,32] 77 | f.states[bucket] = f.states[bucket] | 1< 1 to be edge") 14 | } 15 | 16 | if directedGraph.IsEdge(1, 0) { 17 | t.Fatalf("expect 1 -> 0 not to be edge") 18 | } 19 | 20 | directedGraph.RemoveEdge(0, 1) 21 | if directedGraph.IsEdge(0, 1) { 22 | t.Fatalf("expect 0 -> 1 not to be edge (should be removed)") 23 | } 24 | 25 | directedGraph.AddEdge(0, 1, 1) 26 | directedGraph.AddEdge(0, 2, 1) 27 | directedGraph.AddEdge(0, 3, 1) 28 | if got, want := directedGraph.Neighbours(0), []int{1, 2, 3}; !reflect.DeepEqual(got, want) { 29 | t.Fatalf("Neighbours %#v, want %#v", got, want) 30 | } 31 | 32 | } 33 | 34 | func TestUndirectedGraph(t *testing.T) { 35 | undirectedGraph := NewGraph(10, false) 36 | 37 | undirectedGraph.AddEdge(0, 1, 1) 38 | if !undirectedGraph.IsEdge(0, 1) || !undirectedGraph.IsEdge(1, 0) { 39 | t.Fatalf("expect 1 - 0 to be edge") 40 | } 41 | 42 | undirectedGraph.RemoveEdge(0, 1) 43 | if undirectedGraph.IsEdge(0, 1) || undirectedGraph.IsEdge(1, 0) { 44 | t.Fatalf("expect 0 - 1 not to be edge") 45 | } 46 | 47 | undirectedGraph.AddEdge(0, 1, 1) 48 | undirectedGraph.AddEdge(0, 2, 1) 49 | undirectedGraph.AddEdge(0, 3, 1) 50 | if got, want := undirectedGraph.Neighbours(0), []int{1, 2, 3}; !reflect.DeepEqual(got, want) { 51 | t.Fatalf("Neighbours %#v, want %#v", got, want) 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /datastructure/priority-queue.go: -------------------------------------------------------------------------------- 1 | package datastructure 2 | 3 | import ( 4 | "container/heap" 5 | ) 6 | 7 | type PriorityQueue struct { 8 | h heap.Interface 9 | } 10 | 11 | func NewPriorityQueue(h heap.Interface) *PriorityQueue { 12 | heap.Init(h) 13 | return &PriorityQueue{ 14 | h: h, 15 | } 16 | } 17 | 18 | func (q *PriorityQueue) Enqueue(v interface{}) { 19 | heap.Push(q.h, v) 20 | } 21 | 22 | func (q *PriorityQueue) Dequeue() interface{} { 23 | return heap.Pop(q.h) 24 | } 25 | -------------------------------------------------------------------------------- /datastructure/priority-queue_test.go: -------------------------------------------------------------------------------- 1 | package datastructure 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | type intHeap []int 9 | 10 | func (h intHeap) Len() int { 11 | return len(h) 12 | } 13 | func (h intHeap) Less(i, j int) bool { 14 | return h[i] > h[j] 15 | } 16 | func (h intHeap) Swap(i, j int) { 17 | h[i], h[j] = h[j], h[i] 18 | } 19 | 20 | func (h *intHeap) Push(v interface{}) { 21 | *h = append(*h, v.(int)) 22 | } 23 | func (h *intHeap) Pop() interface{} { 24 | old := *h 25 | n := len(old) 26 | 27 | x := old[n-1] 28 | *h = old[0 : n-1] 29 | 30 | return x 31 | } 32 | 33 | func TestPriorityQueue(t *testing.T) { 34 | 35 | h := &intHeap{0} 36 | pq := NewPriorityQueue(h) 37 | 38 | pq.Enqueue(10) 39 | pq.Enqueue(5) 40 | pq.Enqueue(20) 41 | 42 | got := make([]int, 0, 4) 43 | for h.Len() > 0 { 44 | got = append(got, pq.Dequeue().(int)) 45 | } 46 | 47 | want := []int{20, 10, 5, 0} 48 | if !reflect.DeepEqual(got, want) { 49 | t.Fatalf("got %v, want %v", got, want) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /datastructure/queue.go: -------------------------------------------------------------------------------- 1 | package datastructure 2 | 3 | import "fmt" 4 | 5 | type Queue struct { 6 | data []interface{} 7 | } 8 | 9 | func (q *Queue) Enqueue(v interface{}) { 10 | q.data = append(q.data, v) 11 | } 12 | 13 | func (q *Queue) Dequeue() (interface{}, error) { 14 | if len(q.data) == 0 { 15 | return nil, fmt.Errorf("empty") 16 | } 17 | 18 | v := q.data[0] 19 | q.data = q.data[1:] 20 | return v, nil 21 | } 22 | -------------------------------------------------------------------------------- /datastructure/queue_test.go: -------------------------------------------------------------------------------- 1 | package datastructure 2 | 3 | import "testing" 4 | 5 | func TestQueue(t *testing.T) { 6 | inputs := []int{1, 2, 3, 4, 5} 7 | queue := &Queue{} 8 | 9 | for _, input := range inputs { 10 | queue.Enqueue(input) 11 | } 12 | 13 | var v interface{} 14 | for i := 0; i < len(inputs); i++ { 15 | var err error 16 | v, err = queue.Dequeue() 17 | if err != nil { 18 | t.Fatal("err:", err) 19 | } 20 | } 21 | if got, want := v.(int), 5; got != want { 22 | t.Fatalf("got %v, want %v", got, want) 23 | 24 | } 25 | 26 | if _, err := queue.Dequeue(); err == nil { 27 | t.Fatalf("expect to be failed") 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /datastructure/stack.go: -------------------------------------------------------------------------------- 1 | package datastructure 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type Stack struct { 8 | data []interface{} 9 | } 10 | 11 | func (s *Stack) Push(v interface{}) { 12 | s.data = append(s.data, v) 13 | } 14 | 15 | func (s *Stack) Pop() (interface{}, error) { 16 | if len(s.data) == 0 { 17 | return nil, fmt.Errorf("empty") 18 | } 19 | 20 | v := s.data[len(s.data)-1] 21 | s.data = s.data[0 : len(s.data)-1] 22 | return v, nil 23 | } 24 | -------------------------------------------------------------------------------- /datastructure/stack_test.go: -------------------------------------------------------------------------------- 1 | package datastructure 2 | 3 | import "testing" 4 | 5 | func TestStack(t *testing.T) { 6 | inputs := []int{1, 2, 3, 4, 5} 7 | stack := &Stack{} 8 | 9 | for _, input := range inputs { 10 | stack.Push(input) 11 | } 12 | 13 | var v interface{} 14 | for i := 0; i < len(inputs); i++ { 15 | var err error 16 | v, err = stack.Pop() 17 | if err != nil { 18 | t.Fatal("err:", err) 19 | } 20 | } 21 | 22 | if got, want := v.(int), 1; got != want { 23 | t.Fatalf("got %v, want %v", got, want) 24 | } 25 | 26 | if _, err := stack.Pop(); err == nil { 27 | t.Fatalf("expect to be failed") 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /graph/bellman-ford.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/tcnksm/go-algorithms/datastructure" 7 | ) 8 | 9 | func BellmanFord(graph *datastructure.Graph, s int, dist []int) error { 10 | for i := 0; i < len(dist); i++ { 11 | if i == s { 12 | dist[i] = 0 13 | continue 14 | } 15 | dist[i] = inf 16 | } 17 | 18 | // We need, at least, n-1 times inspection 19 | for i := 0; i <= graph.N; i++ { 20 | 21 | for u := 0; u < graph.N; u++ { 22 | for _, v := range graph.Neighbours(u) { 23 | newDist := dist[u] + graph.Edge(u, v) 24 | if newDist < dist[v] { 25 | if i == graph.N { 26 | return fmt.Errorf("graph has negative cycle") 27 | } 28 | 29 | dist[v] = newDist 30 | } 31 | } 32 | } 33 | } 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /graph/bellman-ford_test.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/tcnksm/go-algorithms/datastructure" 8 | ) 9 | 10 | func testGraphWithNegative(t *testing.T) (*datastructure.Graph, []int) { 11 | directedGraph := datastructure.NewGraph(5, true) 12 | 13 | directedGraph.AddEdge(0, 4, 2) 14 | directedGraph.AddEdge(4, 3, 4) 15 | directedGraph.AddEdge(4, 1, 5) 16 | directedGraph.AddEdge(3, 2, 6) 17 | directedGraph.AddEdge(1, 3, -2) 18 | directedGraph.AddEdge(2, 1, -3) 19 | 20 | want := []int{0, 7, 11, 5, 2} 21 | 22 | return directedGraph, want 23 | } 24 | 25 | func TestBellmanFord(t *testing.T) { 26 | directedGraph, want := testGraphWithNegative(t) 27 | dist := make([]int, 5) 28 | if err := BellmanFord(directedGraph, 0, dist); err != nil { 29 | t.Fatalf("err: %s", err) 30 | } 31 | 32 | if !reflect.DeepEqual(dist, want) { 33 | t.Fatalf("got %v, want %v", dist, want) 34 | } 35 | } 36 | 37 | func TestBellmanFord_negative_cycle(t *testing.T) { 38 | directedGraph := datastructure.NewGraph(5, true) 39 | 40 | directedGraph.AddEdge(0, 4, 2) 41 | directedGraph.AddEdge(4, 3, 4) 42 | directedGraph.AddEdge(4, 1, 5) 43 | directedGraph.AddEdge(3, 2, 6) 44 | directedGraph.AddEdge(1, 3, -2) 45 | directedGraph.AddEdge(2, 1, -5) 46 | 47 | dist := make([]int, 5) 48 | if err := BellmanFord(directedGraph, 0, dist); err == nil { 49 | t.Fatalf("expect to be failed: %v", dist) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /graph/breadth-first-search.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import "github.com/tcnksm/go-algorithms/datastructure" 4 | 5 | // O(V+E) 6 | // 7 | // V is number of vertics, E is number of edges 8 | func BreadthFirstSearch(graph *datastructure.Graph, s int, fn func(i int)) error { 9 | visited := make([]int, graph.N) 10 | queue := &datastructure.Queue{} 11 | queue.Enqueue(s) 12 | 13 | for { 14 | v, err := queue.Dequeue() 15 | if err != nil { 16 | break 17 | } 18 | 19 | i := v.(int) 20 | if visited[i] == 1 { 21 | continue 22 | } 23 | 24 | visited[i] = 1 25 | fn(i) 26 | 27 | for _, j := range graph.Neighbours(i) { 28 | queue.Enqueue(j) 29 | } 30 | 31 | } 32 | return nil 33 | } 34 | -------------------------------------------------------------------------------- /graph/depth-first-search.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import "github.com/tcnksm/go-algorithms/datastructure" 4 | 5 | // O(V+E) 6 | // 7 | // V is number of vertics, E is number of edges 8 | func DepthFirstSearch(graph *datastructure.Graph, s int, fn func(i int)) error { 9 | visited := make([]int, graph.N) 10 | stack := &datastructure.Stack{} 11 | stack.Push(s) 12 | 13 | for { 14 | v, err := stack.Pop() 15 | if err != nil { 16 | break 17 | } 18 | 19 | i := v.(int) 20 | if visited[i] == 1 { 21 | continue 22 | } 23 | 24 | visited[i] = 1 25 | fn(i) 26 | 27 | for _, j := range graph.Neighbours(i) { 28 | stack.Push(j) 29 | } 30 | } 31 | 32 | return nil 33 | } 34 | -------------------------------------------------------------------------------- /graph/dijkstra.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "container/heap" 5 | 6 | "github.com/tcnksm/go-algorithms/datastructure" 7 | ) 8 | 9 | const ( 10 | inf int = 1 << 62 11 | ) 12 | 13 | type vertex struct { 14 | id int 15 | dist *int 16 | } 17 | 18 | type priorityQueue []vertex 19 | 20 | func (q priorityQueue) Len() int { return len(q) } 21 | func (q priorityQueue) Less(i, j int) bool { return *q[i].dist < *q[j].dist } 22 | func (q priorityQueue) Swap(i, j int) { q[i], q[j] = q[j], q[i] } 23 | func (q *priorityQueue) Push(v interface{}) { 24 | *q = append(*q, v.(vertex)) 25 | } 26 | 27 | func (q *priorityQueue) Pop() interface{} { 28 | old := *q 29 | n := len(old) 30 | v := old[n-1] 31 | *q = old[0 : n-1] 32 | return v 33 | } 34 | 35 | // O((V+E)logV) 36 | func Dijkstra(graph *datastructure.Graph, s int, dist []int) error { 37 | pq := make(priorityQueue, 0, graph.N) 38 | heap.Init(&pq) 39 | 40 | // Initialize dist, O(V*logV) 41 | for i := 0; i < graph.N; i++ { 42 | dist[i] = inf 43 | if i == s { 44 | dist[i] = 0 45 | } 46 | 47 | heap.Push(&pq, vertex{ 48 | id: i, 49 | dist: &dist[i], 50 | }) 51 | } 52 | 53 | // O(E*logV) 54 | for pq.Len() > 0 { 55 | u := heap.Pop(&pq).(vertex).id 56 | for _, v := range graph.Neighbours(u) { 57 | newDist := dist[u] + graph.Edge(u, v) 58 | if newDist < dist[v] { 59 | dist[v] = newDist 60 | } 61 | } 62 | 63 | // Better to use Fix function 64 | // How to know index which is fixed 65 | heap.Init(&pq) 66 | } 67 | 68 | return nil 69 | } 70 | 71 | // Without heap 72 | func DijkstraDG(graph *datastructure.Graph, s int, dist []int) error { 73 | visited := make([]bool, graph.N, graph.N) 74 | for i := 0; i < graph.N; i++ { 75 | if i == s { 76 | dist[i] = 0 77 | continue 78 | } 79 | dist[i] = inf 80 | } 81 | 82 | for { 83 | 84 | // Find V(u) which is not visited 85 | u := -1 86 | for i := 0; i < graph.N; i++ { 87 | if !visited[i] && dist[i] < inf { 88 | u = i 89 | } 90 | } 91 | 92 | if u == -1 { 93 | break 94 | } 95 | 96 | visited[u] = true 97 | for _, v := range graph.Neighbours(u) { 98 | newDist := dist[u] + graph.Edge(u, v) 99 | if newDist < dist[v] { 100 | dist[v] = newDist 101 | } 102 | } 103 | } 104 | 105 | return nil 106 | } 107 | -------------------------------------------------------------------------------- /graph/dijkstra_test.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/tcnksm/go-algorithms/datastructure" 8 | ) 9 | 10 | func testGraphShortestPath(t *testing.T) (*datastructure.Graph, []int) { 11 | directedGraph := datastructure.NewGraph(6, true) 12 | 13 | directedGraph.AddEdge(0, 1, 6) 14 | directedGraph.AddEdge(0, 2, 8) 15 | directedGraph.AddEdge(0, 3, 18) 16 | directedGraph.AddEdge(1, 4, 11) 17 | directedGraph.AddEdge(4, 5, 3) 18 | directedGraph.AddEdge(5, 3, 4) 19 | directedGraph.AddEdge(5, 2, 7) 20 | directedGraph.AddEdge(2, 3, 9) 21 | 22 | // dist[5] mean shortest distance (weight) 23 | // from vertex 0 to vertex 5 24 | want := []int{0, 6, 8, 17, 17, 20} 25 | 26 | return directedGraph, want 27 | } 28 | 29 | func TestDijkstra(t *testing.T) { 30 | directedGraph, want := testGraphShortestPath(t) 31 | dist := make([]int, 6) 32 | if err := Dijkstra(directedGraph, 0, dist); err != nil { 33 | t.Fatalf("err: %s", err) 34 | } 35 | 36 | if !reflect.DeepEqual(dist, want) { 37 | t.Fatalf("got %v, want %v", dist, want) 38 | } 39 | } 40 | 41 | func TestDijkstraDG(t *testing.T) { 42 | directedGraph, want := testGraphShortestPath(t) 43 | 44 | dist := make([]int, 6) 45 | if err := DijkstraDG(directedGraph, 0, dist); err != nil { 46 | t.Fatalf("err: %s", err) 47 | } 48 | 49 | if !reflect.DeepEqual(dist, want) { 50 | t.Fatalf("got %v, want %v", dist, want) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /graph/search_test.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/tcnksm/go-algorithms/datastructure" 8 | ) 9 | 10 | func testGraphSearch(t *testing.T, directed bool) *datastructure.Graph { 11 | directedGraph := datastructure.NewGraph(10, directed) 12 | 13 | // 0 14 | // / | \ 15 | // 1 2 3 16 | // / \ / \ / 17 | // 4 5 6 7 8 18 | // / 19 | // 9 20 | directedGraph.AddEdge(0, 1, 1) 21 | directedGraph.AddEdge(0, 2, 1) 22 | directedGraph.AddEdge(0, 3, 1) 23 | directedGraph.AddEdge(1, 4, 1) 24 | directedGraph.AddEdge(1, 5, 1) 25 | directedGraph.AddEdge(2, 6, 1) 26 | directedGraph.AddEdge(2, 7, 1) 27 | directedGraph.AddEdge(3, 8, 1) 28 | directedGraph.AddEdge(4, 9, 1) 29 | 30 | return directedGraph 31 | } 32 | 33 | func TestDFS(t *testing.T) { 34 | for _, directed := range []bool{true, false} { 35 | graph := testGraphSearch(t, directed) 36 | want := []int{0, 3, 8, 2, 7, 6, 1, 5, 4, 9} 37 | 38 | got := make([]int, 0, 10) 39 | err := DepthFirstSearch(graph, 0, func(i int) { 40 | got = append(got, i) 41 | }) 42 | 43 | if err != nil { 44 | t.Fatalf("err: %s", err) 45 | } 46 | 47 | if !reflect.DeepEqual(got, want) { 48 | t.Fatalf("got %v, want %v", got, want) 49 | } 50 | } 51 | } 52 | 53 | func TestBFS(t *testing.T) { 54 | for _, directed := range []bool{true, false} { 55 | graph := testGraphSearch(t, directed) 56 | want := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 57 | 58 | got := make([]int, 0, 10) 59 | err := BreadthFirstSearch(graph, 0, func(i int) { 60 | got = append(got, i) 61 | }) 62 | 63 | if err != nil { 64 | t.Fatalf("err: %s", err) 65 | } 66 | 67 | if !reflect.DeepEqual(got, want) { 68 | t.Fatalf("got %v, want %v", got, want) 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /search/benchmark_test.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "math/rand" 7 | "sort" 8 | "testing" 9 | ) 10 | 11 | // randomArray returns random array but inject the given 12 | // value x at index p. 13 | func randomArray(n, p, x int) []int { 14 | a := make([]int, n) 15 | for i := 0; i < n; i++ { 16 | if i == p { 17 | a[i] = x 18 | continue 19 | } 20 | a[i] = rand.Intn(n) 21 | } 22 | 23 | return a 24 | } 25 | 26 | func BenchmarkBinary(b *testing.B) { 27 | l := 1 << 20 28 | b.Run(fmt.Sprintf("%d", l), func(b *testing.B) { 29 | b.StopTimer() 30 | x := rand.Intn(l) 31 | a := randomArray(l, rand.Intn(l-1), x) 32 | sort.Ints(a) 33 | b.StartTimer() 34 | for i := 0; i < b.N; i++ { 35 | if !Binary(a, x) { 36 | b.Fatalf("expect %d to be found", x) 37 | } 38 | b.StopTimer() 39 | } 40 | }) 41 | } 42 | 43 | func BenchmarkHash(b *testing.B) { 44 | for k := uint(8); k <= 16; k++ { 45 | l := 1 << k 46 | b.Run(fmt.Sprintf("%d", l), func(b *testing.B) { 47 | b.StopTimer() 48 | x := rand.Intn(l) 49 | a := randomArray(l, l/2, x) 50 | b.StartTimer() 51 | 52 | ht := NewHashTable(a, int(math.Pow(2, 10))-1) 53 | for i := 0; i < b.N; i++ { 54 | if ht.Search(x) { 55 | b.Fatal("expect to be found") 56 | } 57 | } 58 | }) 59 | } 60 | } 61 | 62 | func BenchmarkSequential(b *testing.B) { 63 | for k := uint(8); k <= 16; k++ { 64 | l := 1 << k 65 | b.Run(fmt.Sprintf("%d", l), func(b *testing.B) { 66 | b.StopTimer() 67 | x := 124 68 | a := randomArray(l, l/2, x) 69 | b.StartTimer() 70 | for i := 0; i < b.N; i++ { 71 | if !Sequential(a, x) { 72 | b.Fatal("expect to be found") 73 | } 74 | } 75 | }) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /search/binary-tree.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | import "github.com/tcnksm/go-algorithms/datastructure" 4 | 5 | // Binary Search Tree is very suited when you need to 6 | // add (insert) new elements very often. 7 | func NewBinaryTree(a []int) *datastructure.BinaryTree { 8 | less := func(x, y interface{}) bool { 9 | i, j := x.(int), y.(int) 10 | return i < j 11 | } 12 | 13 | tree := datastructure.NewBinaryTree(less) 14 | for i := 0; i < len(a); i++ { 15 | tree.Insert(a[i]) 16 | } 17 | 18 | return tree 19 | } 20 | -------------------------------------------------------------------------------- /search/binary.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | // Binary search search sorted slice a contains x. 4 | // 5 | // Best: O(1) 6 | // Worst: O(log n) 7 | // Average: O(log n) 8 | func Binary(a []int, x int) bool { 9 | left, right := 0, len(a) 10 | for left <= right { 11 | index := left + (right-left)/2 12 | if a[index] == x { 13 | return true 14 | } 15 | 16 | if x < a[index] { 17 | right = index - 1 18 | } else { 19 | left = index + 1 20 | } 21 | } 22 | return false 23 | } 24 | -------------------------------------------------------------------------------- /search/hash.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | type HashTable struct { 4 | table [][]int 5 | size int 6 | } 7 | 8 | func NewHashTable(a []int, size int) *HashTable { 9 | ht := &HashTable{ 10 | table: make([][]int, size), 11 | size: size, 12 | } 13 | 14 | for i := 0; i < len(a); i++ { 15 | index := ht.hash(a[i]) 16 | ht.table[index%size] = append(ht.table[index%size], a[i]) 17 | } 18 | 19 | return ht 20 | } 21 | 22 | func (h *HashTable) hash(x int) int { 23 | v := x % h.size 24 | if x < 0 { 25 | return -v 26 | } 27 | return v 28 | } 29 | 30 | func (h *HashTable) Search(x int) bool { 31 | index := h.hash(x) 32 | l := h.table[index%h.size] 33 | if len(l) == 0 { 34 | return false 35 | } 36 | 37 | for i := 0; i < len(l); i++ { 38 | if l[i] == x { 39 | return true 40 | } 41 | } 42 | 43 | return false 44 | } 45 | -------------------------------------------------------------------------------- /search/search_test.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | import ( 4 | "math" 5 | "sort" 6 | "testing" 7 | ) 8 | 9 | var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586} 10 | 11 | func TestSequential(t *testing.T) { 12 | data := ints 13 | a := data[:] 14 | if got := Sequential(a, 42); !got { 15 | t.Errorf("Search=%v, want=true", got) 16 | } 17 | 18 | if got := Sequential(a, 43); got { 19 | t.Errorf("Search=%v, want=false", got) 20 | } 21 | } 22 | 23 | func TestBinary(t *testing.T) { 24 | data := ints 25 | a := data[:] 26 | sort.Ints(a) 27 | if got := Binary(a, 42); !got { 28 | t.Errorf("Search=%v, want=true", got) 29 | } 30 | 31 | if got := Binary(a, 43); got { 32 | t.Errorf("Search=%v, want=false", got) 33 | } 34 | } 35 | 36 | func TestHash(t *testing.T) { 37 | data := ints 38 | a := data[:] 39 | ht := NewHashTable(a, int(math.Pow(2, 10))-1) 40 | 41 | if got := ht.Search(42); !got { 42 | t.Errorf("Search=%v, want=true", got) 43 | } 44 | 45 | if got := ht.Search(43); got { 46 | t.Errorf("Search=%v, want=false", got) 47 | } 48 | } 49 | 50 | func TestBinaryTree(t *testing.T) { 51 | data := ints 52 | a := data[:] 53 | tree := NewBinaryTree(a) 54 | 55 | if got := tree.Search(42); !got { 56 | t.Errorf("Search=%v, want=true", got) 57 | } 58 | 59 | if got := tree.Search(43); got { 60 | t.Errorf("Search=%v, want=false", got) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /search/sequential.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | // Sequential search 4 | // 5 | // Best: O(1) 6 | // Worst: O(n) 7 | // Average: O(n) 8 | func Sequential(a []int, x int) bool { 9 | for i := 0; i < len(a); i++ { 10 | if a[i] == x { 11 | return true 12 | } 13 | } 14 | return false 15 | } 16 | -------------------------------------------------------------------------------- /sort/README.md: -------------------------------------------------------------------------------- 1 | # Sort 2 | 3 | The followings are benchmarking result. 4 | 5 | | name | times | ns/op | B/op | allocs/op | 6 | | :---: | ---: | ---: | ---: | ---: | 7 | |BenchmarkSort1K/Quick-4|30000|53654|0|0| 8 | |BenchmarkSort1K/Shell-4|20000|89352|0|0| 9 | |BenchmarkSort1K/Merge-4|10000|103946|81920|1023| 10 | |BenchmarkSort1K/Heap-4|10000|102479|0|0| 11 | |BenchmarkSort1K/Bucket-4|10000|224558|36757|781| 12 | |BenchmarkSort1K/Std-4|10000|122410|32|1| 13 | |BenchmarkSort1K/Insert-4|3000|437806|0|0| 14 | |BenchmarkSort1K/Select-4|2000|1025890|0|0| 15 | |BenchmarkSort1K/Bubble-4|2000|1249174|0|0| 16 | 17 | 18 | ![sort-random-1K](doc/sort-random-1K.png) 19 | 20 | [https://docs.google.com/spreadsheets/d/1cdkryOQ8jA0TcfHctMHHLvXWGEMU86kDs4EPhnQuebk](https://docs.google.com/spreadsheets/d/1cdkryOQ8jA0TcfHctMHHLvXWGEMU86kDs4EPhnQuebk/edit?usp=sharing) 21 | 22 | ## Tips 23 | 24 | To compare performance use [`benchcmp`](https://godoc.org/golang.org/x/tools/cmd/benchcmp) 25 | 26 | ```bash 27 | $ go get golang.org/x/tools/cmd/benchcmp 28 | $ go test -bench . -benchmem -cpuprofile cpu.prof > old.txt 29 | $ go test -bench . -bemchmem -cpuprofile cpu.prof > new.txt 30 | $ benchcmp old.txt new.txt 31 | ``` 32 | 33 | To visualize cmp, 34 | 35 | ```bash 36 | $ go get github.com/ajstarks/svgo/benchviz 37 | $ benchcmp old.txt new.txt | benchviz > output.svg 38 | ``` 39 | 40 | To check cpu profile, 41 | 42 | ```bash 43 | $ go test -bench . -benchmem -cpuprofile cpu.prof 44 | $ go tool pprof sort.test cpu.prof 45 | ``` 46 | 47 | (Why `sort.test` is required ? To find simbol localtion) 48 | 49 | To check memory allocation, 50 | 51 | ```bash 52 | $ go test -bench . -benchmem -memprofile mem.prof 53 | $ go tool pprof -alloc_objects sort.test mem.prof 54 | ``` 55 | 56 | To generate markdown table, 57 | 58 | ```bash 59 | $ go get github.com/tcnksm/misc/cmd/benchtable 60 | $ go test -bench . -benchmem | benchtable 61 | ``` 62 | -------------------------------------------------------------------------------- /sort/benchmark_test.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "testing" 7 | ) 8 | 9 | func BenchmarkSort1K(b *testing.B) { 10 | for _, bc := range cases { 11 | b.Run(fmt.Sprintf("%s", bc.Name), func(b *testing.B) { 12 | b.StopTimer() 13 | for i := 0; i < b.N; i++ { 14 | data := make([]int, 1<<10) 15 | for i := 0; i < len(data); i++ { 16 | data[i] = rand.Intn(1 << 10) 17 | } 18 | b.StartTimer() 19 | bc.Func(data) 20 | b.StopTimer() 21 | } 22 | }) 23 | } 24 | } 25 | 26 | func BenchmarkSortSorted(b *testing.B) { 27 | for _, bc := range cases { 28 | b.Run(fmt.Sprintf("%s", bc.Name), func(b *testing.B) { 29 | b.StopTimer() 30 | for i := 0; i < b.N; i++ { 31 | data := make([]int, 1<<10) 32 | for i := 0; i < len(data); i++ { 33 | data[i] = i 34 | } 35 | b.StartTimer() 36 | bc.Func(data) 37 | b.StopTimer() 38 | } 39 | }) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /sort/bubble.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | func Bubble(a []int) { 4 | for i := 0; i < len(a); i++ { 5 | for j := 0; j < len(a)-1; j++ { 6 | if a[j] > a[j+1] { 7 | a[j], a[j+1] = a[j+1], a[j] 8 | } 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /sort/bucket.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | import "math" 4 | 5 | // TODO: Set ideal number of bucket and hash function. 6 | var bucket = int(math.Pow(2, 10)) - 1 7 | 8 | func hash(x int) int { 9 | return x % bucket 10 | } 11 | 12 | func Bucket(a []int) { 13 | b := make(map[int][]int, bucket) 14 | for i := 0; i < len(a); i++ { 15 | k := hash(a[i]) 16 | b[k] = append(b[k], a[i]) 17 | } 18 | 19 | extract(b, a) 20 | } 21 | 22 | func extract(b map[int][]int, a []int) { 23 | 24 | insertSort := func(a []int) { 25 | for i := 1; i < len(a); i++ { 26 | j := i 27 | for j > 0 && a[j-1] > a[j] { 28 | a[j-1], a[j] = a[j], a[j-1] 29 | j-- 30 | } 31 | } 32 | } 33 | 34 | index := 0 35 | for i := 0; i < bucket; i++ { 36 | insertSort(b[i]) 37 | for m := 0; m < len(b[i]); m++ { 38 | a[index] = b[i][m] 39 | index++ 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /sort/bucket_test.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | import ( 4 | "sort" 5 | "testing" 6 | ) 7 | 8 | func TestBucket(t *testing.T) { 9 | ints := [...]int{7, 5, 13, 2, 14, 1, 6} 10 | data := ints 11 | a := data[:] 12 | Bucket(a) 13 | if !sort.IsSorted(sort.IntSlice(a)) { 14 | t.Errorf("sorted %v", ints) 15 | t.Errorf(" got %v", data) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /sort/counting.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | // Counting can be used only if elements of a is 4 | // 0 <= i < k and k should be much smaller than len(a). 5 | func Counting(a []int, k int) { 6 | b := make(map[int]int, k) 7 | for i := 0; i < len(a); i++ { 8 | b[a[i]]++ 9 | } 10 | 11 | index := 0 12 | for i := 0; i <= k; i++ { 13 | for b[i] > 0 { 14 | a[index] = i 15 | b[i]-- 16 | index++ 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /sort/counting_test.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | import ( 4 | "math/rand" 5 | "sort" 6 | "testing" 7 | ) 8 | 9 | func TestCounting(t *testing.T) { 10 | k := 10 11 | a := make([]int, 100) 12 | for i := 0; i < 100; i++ { 13 | a[i] = rand.Intn(k) 14 | } 15 | 16 | Counting(a, k) 17 | if !sort.IsSorted(sort.IntSlice(a)) { 18 | t.Errorf("got %v", a) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /sort/doc/sort-random-1K.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnksm/go-algorithms/179e7f9908ea5d9bc5d929d22b71e323cf8e08cb/sort/doc/sort-random-1K.png -------------------------------------------------------------------------------- /sort/heap.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | func Heap(a []int) { 4 | buildHeap(a) 5 | for i := len(a) - 1; i >= 0; i-- { 6 | a[0], a[i] = a[i], a[0] 7 | heapify(a, 0, i) 8 | } 9 | 10 | } 11 | 12 | func buildHeap(a []int) { 13 | for i := (len(a))/2 - 1; i >= 0; i-- { 14 | heapify(a, i, len(a)) 15 | } 16 | } 17 | 18 | func heapify(a []int, index, max int) { 19 | left := 2*index + 1 20 | right := 2*index + 2 21 | 22 | // Find largest value in a[index],a[left] and a[right] 23 | largest := index 24 | if left < max && a[left] > a[index] { 25 | largest = left 26 | } 27 | 28 | if right < max && a[right] > a[largest] { 29 | largest = right 30 | } 31 | 32 | if index != largest { 33 | a[index], a[largest] = a[largest], a[index] 34 | heapify(a, largest, max) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /sort/insert.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | // Insert sorts https://en.wikipedia.org/wiki/Insertion_sort 4 | func Insert(a []int) { 5 | for i := 0; i < len(a); i++ { 6 | // Get element one by one and compare with elements 7 | // which are already sorted. 8 | for j := i; j > 0 && a[j-1] > a[j]; j-- { 9 | a[j-1], a[j] = a[j], a[j-1] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /sort/merge.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | func Merge(a []int) { 4 | merge(a, 0, len(a)-1) 5 | } 6 | 7 | func merge(a []int, start, end int) { 8 | if start >= end { 9 | return 10 | } 11 | 12 | m := (start + end) / 2 13 | merge(a, start, m) 14 | merge(a, m+1, end) 15 | 16 | // It's difficult to merge 2 array in-place 17 | var index int 18 | b := make([]int, end-start+1) 19 | 20 | i := start 21 | j := m + 1 22 | for { 23 | if i > m || j > end { 24 | break 25 | } 26 | 27 | if a[i] <= a[j] { 28 | b[index] = a[i] 29 | index++ 30 | i++ 31 | } else { 32 | b[index] = a[j] 33 | index++ 34 | j++ 35 | } 36 | } 37 | 38 | for i <= m { 39 | b[index] = a[i] 40 | index++ 41 | i++ 42 | } 43 | 44 | for j <= end { 45 | b[index] = a[j] 46 | index++ 47 | j++ 48 | } 49 | 50 | n := 0 51 | for k := start; k <= end; k++ { 52 | a[k] = b[n] 53 | n++ 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /sort/quick.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | func Quick(a []int) { 4 | quick(a, 0, len(a)-1) 5 | } 6 | 7 | func quick(a []int, left, right int) { 8 | if left >= right { 9 | return 10 | } 11 | 12 | pi := partition(a, left, right) 13 | quick(a, left, pi-1) 14 | quick(a, pi+1, right) 15 | } 16 | 17 | func partition(a []int, left, right int) int { 18 | p := left 19 | a[p], a[right] = a[right], a[p] 20 | 21 | store := left 22 | for i := left; i < right; i++ { 23 | if a[i] <= a[right] { 24 | a[store], a[i] = a[i], a[store] 25 | store++ 26 | } 27 | } 28 | 29 | a[right], a[store] = a[store], a[right] 30 | return store 31 | } 32 | 33 | // QuickSimple is simple implementation of quick sort 34 | // but it's slow and needs a lot of allocation. 35 | func QuickSimple(a []int) { 36 | quickSimple(a) 37 | } 38 | 39 | func quickSimple(a []int) []int { 40 | if len(a) < 1 { 41 | return a 42 | } 43 | 44 | pivot := a[(len(a)-1)/2] 45 | left := make([]int, 0, len(a)/2) 46 | right := make([]int, 0, len(a)/2) 47 | for i := 1; i < len(a); i++ { 48 | switch { 49 | case a[i] <= pivot: 50 | left = append(left, a[i]) 51 | case a[i] > pivot: 52 | right = append(right, a[i]) 53 | } 54 | } 55 | 56 | left = quickSimple(left) 57 | right = quickSimple(right) 58 | 59 | left = append(left, pivot) 60 | left = append(left, right...) 61 | return left 62 | } 63 | -------------------------------------------------------------------------------- /sort/quick_test.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | import ( 4 | "sort" 5 | "testing" 6 | ) 7 | 8 | func TestQuickSimple(t *testing.T) { 9 | data := ints 10 | a := data[:] 11 | a = quickSimple(a) 12 | if !sort.IsSorted(sort.IntSlice(a)) { 13 | t.Errorf("sorted %v", ints) 14 | t.Errorf(" got %v", data) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sort/selection.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | func Selection(a []int) { 4 | for i := 0; i < len(a); i++ { 5 | j := selectMin(a, i) 6 | if j != i { 7 | a[i], a[j] = a[j], a[i] 8 | } 9 | } 10 | } 11 | 12 | func selectMin(a []int, left int) int { 13 | index := left 14 | for i := left; i < len(a); i++ { 15 | if a[i] < a[index] { 16 | index = i 17 | } 18 | } 19 | 20 | return index 21 | } 22 | -------------------------------------------------------------------------------- /sort/shell.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | // Shell sort is improvement of Insert sort 4 | func Shell(a []int) { 5 | for h := len(a) / 3; h > 0; h /= 3 { 6 | for i := h; i < len(a); i++ { 7 | for j := i; j >= h && a[j-h] > a[j]; j -= h { 8 | a[j-h], a[j] = a[j], a[j-h] 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /sort/sort_test.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | import ( 4 | "sort" 5 | "testing" 6 | ) 7 | 8 | var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586} 9 | 10 | var cases = []struct { 11 | Name string 12 | Func func([]int) 13 | SkipTest bool 14 | }{ 15 | 16 | { 17 | "Quick", 18 | Quick, 19 | false, 20 | }, 21 | 22 | { 23 | "Shell", 24 | Shell, 25 | false, 26 | }, 27 | 28 | { 29 | "Merge", 30 | Merge, 31 | false, 32 | }, 33 | 34 | { 35 | "Heap", 36 | Heap, 37 | false, 38 | }, 39 | 40 | { 41 | "Bucket", 42 | Bucket, 43 | true, 44 | }, 45 | 46 | { 47 | "Std", 48 | sort.Ints, 49 | true, 50 | }, 51 | 52 | { 53 | "Insert", 54 | Insert, 55 | false, 56 | }, 57 | 58 | { 59 | "Select", 60 | Selection, 61 | false, 62 | }, 63 | 64 | { 65 | "Bubble", 66 | Bubble, 67 | false, 68 | }, 69 | } 70 | 71 | func TestSort(t *testing.T) { 72 | for _, tc := range cases { 73 | if tc.SkipTest { 74 | continue 75 | } 76 | 77 | t.Run(tc.Name, func(t *testing.T) { 78 | data := ints 79 | a := data[:] 80 | tc.Func(a) 81 | if !sort.IsSorted(sort.IntSlice(a)) { 82 | t.Errorf("sorted %v", ints) 83 | t.Errorf(" got %v", data) 84 | } 85 | }) 86 | } 87 | } 88 | --------------------------------------------------------------------------------