├── sorting ├── pq │ ├── testdata │ │ ├── m2.txt │ │ ├── m3.txt │ │ ├── m1.txt │ │ └── tinyBatch.txt │ ├── binary_heap_based0.go │ ├── example_index_pq_test.go │ ├── bench_test.go │ ├── binary_heap_based1.go │ ├── priority_queue.go │ ├── example_pq_test.go │ ├── binary_heap.go │ ├── max_pq.go │ └── min_pq.go ├── testdata │ └── words3.txt ├── heap_test.go ├── quick_test.go ├── shell_test.go ├── sorting_test.go ├── mergex_test.go ├── merge_bu_test.go ├── insertion_test.go ├── quick_3way_test.go ├── selection_test.go ├── merge_test.go ├── insertion.go ├── selection.go ├── shell.go ├── bench_test.go ├── quick_3way.go ├── heap.go ├── sorting.go └── example_test.go ├── context └── suffix │ ├── testdata │ ├── abra.txt │ ├── tale.txt.gz │ ├── mobydick.txt.gz │ └── tinyTale.txt │ ├── suffix.go │ ├── suffix_array.go │ └── example_test.go ├── testutil ├── testdata │ ├── ints.txt │ ├── floats.txt │ ├── in.txt │ └── in.txt.gz ├── example_stopwatch_test.go ├── stopwatch.go ├── random.go ├── example_random_test.go ├── example_in_test.go └── in.go ├── cmd ├── context │ ├── kwicx │ │ ├── testdata │ │ │ ├── rune.txt │ │ │ └── tale.txt.gz │ │ └── kwicx.go │ └── kwic │ │ ├── testdata │ │ └── tale.txt.gz │ │ └── kwic.go └── fund │ └── doubling │ ├── doubling_ratio.go │ ├── doubling_tester.go │ └── main.go ├── go.mod ├── fund ├── testdata │ ├── tobe.txt │ ├── tinyAllowlist.txt │ └── tinyText.txt ├── xsum │ ├── testdata │ │ ├── 2Kints.txt.gz │ │ └── 4Kints.txt.gz │ ├── xsum.go │ ├── bench_test.go │ ├── two_sum.go │ ├── three_sum.go │ └── xsum_test.go ├── uf │ ├── testdata │ │ └── tinyUF.txt │ ├── union_find.go │ ├── quick_find.go │ ├── weighted_quick_union.go │ ├── quick_union.go │ ├── uf.go │ └── example_test.go ├── fund.go ├── example_evaluate_test.go ├── linked_list.go ├── binary_search.go ├── bag.go ├── evaluate.go ├── stack.go └── queue.go ├── strings ├── trie │ ├── testdata │ │ └── shellsST.txt │ └── example_test.go ├── strings.go ├── sort │ ├── testdata │ │ ├── shells.txt │ │ └── words3.txt │ ├── sort.go │ ├── quick_3way.go │ ├── msd.go │ ├── example_test.go │ └── lsd.go ├── search │ ├── search.go │ ├── brute_force.go │ ├── kmp.go │ ├── boyer_moore.go │ ├── bench_test.go │ ├── rabin_karp.go │ └── search_test.go └── regexp │ ├── example_test.go │ └── nfa.go ├── searching ├── testdata │ ├── tale.txt.gz │ └── tinyTale.txt ├── symbol_table.go ├── ordered_symbol_table.go ├── hash_symbol_table.go ├── example_test.go └── sequential_search.go ├── graphs ├── graph │ ├── testdata │ │ ├── tinyCG.txt │ │ ├── tinyG.txt │ │ └── routes.txt │ ├── depth_first_search.go │ ├── connected_components.go │ ├── depth_first_paths.go │ ├── symbol_graph.go │ └── breadth_first_paths.go ├── digraph │ ├── testdata │ │ ├── movies.txt.gz │ │ ├── tinyDAG.txt │ │ ├── tinyEWD.txt │ │ ├── routes.txt │ │ ├── tinyDG.txt │ │ ├── jobs.txt │ │ └── mediumDG.txt │ ├── directed_edge.go │ ├── directed_dfs.go │ ├── depth_first_directed_paths.go │ ├── directed_cycle.go │ ├── edge_weighted_directed_cycle.go │ ├── kosaraju_sharir_scc.go │ ├── breadth_first_directed_paths.go │ ├── symbol_digraph.go │ ├── topological.go │ ├── digraph.go │ └── depth_first_order.go ├── mst │ ├── testdata │ │ ├── mediumEWG.txt.gz │ │ └── tinyEWG.txt │ ├── prim_mst.go │ ├── edge.go │ ├── kruskal_mst.go │ ├── example_test.go │ ├── lazy_prim_mst.go │ ├── edge_weighted_graph.go │ └── eager_prim_mst.go ├── sp │ ├── testdata │ │ ├── jobsPC.txt │ │ ├── tinyEWDAG.txt │ │ ├── nopath.txt │ │ ├── rates.txt │ │ ├── tinyEWD.txt │ │ ├── tinyEWDn.txt │ │ └── tinyEWDnc.txt │ ├── sp.go │ ├── arbitrage.go │ ├── acyclic_sp.go │ ├── cpm.go │ ├── acyclic_lp.go │ └── dijkstra_sp.go ├── search.go ├── paths.go └── graphs.go ├── .gitignore ├── .github └── workflows │ └── go.yml └── README.md /sorting/pq/testdata/m2.txt: -------------------------------------------------------------------------------- 1 | B D H P Q Q 2 | -------------------------------------------------------------------------------- /sorting/pq/testdata/m3.txt: -------------------------------------------------------------------------------- 1 | A B E F J N 2 | -------------------------------------------------------------------------------- /context/suffix/testdata/abra.txt: -------------------------------------------------------------------------------- 1 | ABRACADABRA! -------------------------------------------------------------------------------- /sorting/pq/testdata/m1.txt: -------------------------------------------------------------------------------- 1 | A B C F G I I Z 2 | -------------------------------------------------------------------------------- /testutil/testdata/ints.txt: -------------------------------------------------------------------------------- 1 | 12 3 -1 2 | 5 3 | 6 -------------------------------------------------------------------------------- /cmd/context/kwicx/testdata/rune.txt: -------------------------------------------------------------------------------- 1 | 你 我 他 2 | 你们 我们 他们 -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/youngzhu/algs4-go 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /testutil/testdata/floats.txt: -------------------------------------------------------------------------------- 1 | 0 0.1 2 | 99.99 100 3 | 0.000009 -------------------------------------------------------------------------------- /testutil/testdata/in.txt: -------------------------------------------------------------------------------- 1 | hello Gopher 2 | wating for you 3 | -------------------------------------------------------------------------------- /fund/testdata/tobe.txt: -------------------------------------------------------------------------------- 1 | to be or not to - be - - that - - - is 2 | -------------------------------------------------------------------------------- /strings/trie/testdata/shellsST.txt: -------------------------------------------------------------------------------- 1 | she sells sea shells by the sea shore -------------------------------------------------------------------------------- /strings/strings.go: -------------------------------------------------------------------------------- 1 | package strings 2 | 3 | const ( 4 | R = 256 // extended ASCII alphabet size 5 | ) -------------------------------------------------------------------------------- /testutil/testdata/in.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngzhu/algs4-go/HEAD/testutil/testdata/in.txt.gz -------------------------------------------------------------------------------- /searching/testdata/tale.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngzhu/algs4-go/HEAD/searching/testdata/tale.txt.gz -------------------------------------------------------------------------------- /fund/xsum/testdata/2Kints.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngzhu/algs4-go/HEAD/fund/xsum/testdata/2Kints.txt.gz -------------------------------------------------------------------------------- /fund/xsum/testdata/4Kints.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngzhu/algs4-go/HEAD/fund/xsum/testdata/4Kints.txt.gz -------------------------------------------------------------------------------- /strings/sort/testdata/shells.txt: -------------------------------------------------------------------------------- 1 | she sells seashells by the sea shore 2 | the shells she sells are surely seashells -------------------------------------------------------------------------------- /context/suffix/testdata/tale.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngzhu/algs4-go/HEAD/context/suffix/testdata/tale.txt.gz -------------------------------------------------------------------------------- /graphs/graph/testdata/tinyCG.txt: -------------------------------------------------------------------------------- 1 | 6 2 | 8 3 | 0 5 4 | 2 4 5 | 2 3 6 | 1 2 7 | 0 1 8 | 3 4 9 | 3 5 10 | 0 2 11 | -------------------------------------------------------------------------------- /cmd/context/kwic/testdata/tale.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngzhu/algs4-go/HEAD/cmd/context/kwic/testdata/tale.txt.gz -------------------------------------------------------------------------------- /graphs/digraph/testdata/movies.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngzhu/algs4-go/HEAD/graphs/digraph/testdata/movies.txt.gz -------------------------------------------------------------------------------- /graphs/mst/testdata/mediumEWG.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngzhu/algs4-go/HEAD/graphs/mst/testdata/mediumEWG.txt.gz -------------------------------------------------------------------------------- /cmd/context/kwicx/testdata/tale.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngzhu/algs4-go/HEAD/cmd/context/kwicx/testdata/tale.txt.gz -------------------------------------------------------------------------------- /context/suffix/testdata/mobydick.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngzhu/algs4-go/HEAD/context/suffix/testdata/mobydick.txt.gz -------------------------------------------------------------------------------- /fund/uf/testdata/tinyUF.txt: -------------------------------------------------------------------------------- 1 | 10 2 | 4 3 3 | 3 8 4 | 6 5 5 | 9 4 6 | 2 1 7 | 8 9 8 | 5 0 9 | 7 2 10 | 6 1 11 | 1 0 12 | 6 7 -------------------------------------------------------------------------------- /fund/testdata/tinyAllowlist.txt: -------------------------------------------------------------------------------- 1 | 84 2 | 48 3 | 68 4 | 10 5 | 18 6 | 98 7 | 12 8 | 23 9 | 54 10 | 57 11 | 33 12 | 16 13 | 77 14 | 11 15 | 29 -------------------------------------------------------------------------------- /fund/testdata/tinyText.txt: -------------------------------------------------------------------------------- 1 | 23 2 | 50 3 | 10 4 | 99 5 | 18 6 | 23 7 | 98 8 | 84 9 | 11 10 | 10 11 | 48 12 | 77 13 | 13 14 | 54 15 | 98 16 | 77 17 | 77 18 | 68 -------------------------------------------------------------------------------- /graphs/graph/testdata/tinyG.txt: -------------------------------------------------------------------------------- 1 | 13 2 | 13 3 | 0 5 4 | 4 3 5 | 0 1 6 | 9 12 7 | 6 4 8 | 5 4 9 | 0 2 10 | 11 12 11 | 9 10 12 | 0 6 13 | 7 8 14 | 9 11 15 | 5 3 16 | -------------------------------------------------------------------------------- /sorting/testdata/words3.txt: -------------------------------------------------------------------------------- 1 | bed bug dad yes zoo 2 | now for tip ilk dim 3 | tag jot sob nob sky 4 | hut men egg few jay 5 | owl joy rap gig wee 6 | was wad fee tap tar 7 | dug jam all bad yet -------------------------------------------------------------------------------- /fund/fund.go: -------------------------------------------------------------------------------- 1 | package fund 2 | 3 | // fundamental 4 | // common structs and interfaces 5 | 6 | type Iterator []interface{} 7 | 8 | type Iterable interface { 9 | Iterator() Iterator 10 | } -------------------------------------------------------------------------------- /graphs/sp/testdata/jobsPC.txt: -------------------------------------------------------------------------------- 1 | 10 2 | 41.0 3 1 7 9 3 | 51.0 1 2 4 | 50.0 0 5 | 36.0 0 6 | 38.0 0 7 | 45.0 0 8 | 21.0 2 3 8 9 | 32.0 2 3 8 10 | 32.0 1 2 11 | 29.0 2 4 6 12 | -------------------------------------------------------------------------------- /strings/sort/testdata/words3.txt: -------------------------------------------------------------------------------- 1 | bed bug dad yes zoo 2 | now for tip ilk dim 3 | tag jot sob nob sky 4 | hut men egg few jay 5 | owl joy rap gig wee 6 | was wad fee tap tar 7 | dug jam all bad yet -------------------------------------------------------------------------------- /graphs/digraph/testdata/tinyDAG.txt: -------------------------------------------------------------------------------- 1 | 13 2 | 15 3 | 2 3 4 | 0 6 5 | 0 1 6 | 2 0 7 | 11 12 8 | 9 12 9 | 9 10 10 | 9 11 11 | 3 5 12 | 8 7 13 | 5 4 14 | 0 5 15 | 6 4 16 | 6 9 17 | 7 6 18 | 19 | -------------------------------------------------------------------------------- /graphs/sp/testdata/tinyEWDAG.txt: -------------------------------------------------------------------------------- 1 | 8 2 | 13 3 | 5 4 0.35 4 | 4 7 0.37 5 | 5 7 0.28 6 | 5 1 0.32 7 | 4 0 0.38 8 | 0 2 0.26 9 | 3 7 0.39 10 | 1 3 0.29 11 | 7 2 0.34 12 | 6 2 0.40 13 | 3 6 0.52 14 | 6 0 0.58 15 | 6 4 0.93 16 | -------------------------------------------------------------------------------- /graphs/sp/testdata/nopath.txt: -------------------------------------------------------------------------------- 1 | 8 2 | 14 3 | 4 5 0.35 4 | 5 4 0.35 5 | 4 7 0.37 6 | 5 7 0.28 7 | 7 5 0.28 8 | 5 1 0.32 9 | 0 4 0.38 10 | 0 2 0.26 11 | 7 3 0.39 12 | 1 3 0.29 13 | 2 7 0.34 14 | 6 2 0.40 15 | 3 6 0.52 16 | 6 4 0.93 17 | -------------------------------------------------------------------------------- /graphs/sp/testdata/rates.txt: -------------------------------------------------------------------------------- 1 | 5 2 | USD 1 0.741 0.657 1.061 1.005 3 | EUR 1.349 1 0.888 1.433 1.366 4 | GBP 1.521 1.126 1 1.614 1.538 5 | CHF 0.942 0.698 0.619 1 0.953 6 | CAD 0.995 0.732 0.650 1.049 1 7 | -------------------------------------------------------------------------------- /graphs/search.go: -------------------------------------------------------------------------------- 1 | package graphs 2 | 3 | // Search find vertices connected to a source vertex s 4 | type Search interface { 5 | Marked(v int) bool // Is v connected to s? 6 | Count() int // How many vertices are connected to s? 7 | } 8 | -------------------------------------------------------------------------------- /graphs/sp/testdata/tinyEWD.txt: -------------------------------------------------------------------------------- 1 | 8 2 | 15 3 | 4 5 0.35 4 | 5 4 0.35 5 | 4 7 0.37 6 | 5 7 0.28 7 | 7 5 0.28 8 | 5 1 0.32 9 | 0 4 0.38 10 | 0 2 0.26 11 | 7 3 0.39 12 | 1 3 0.29 13 | 2 7 0.34 14 | 6 2 0.40 15 | 3 6 0.52 16 | 6 0 0.58 17 | 6 4 0.93 18 | -------------------------------------------------------------------------------- /graphs/digraph/testdata/tinyEWD.txt: -------------------------------------------------------------------------------- 1 | 8 2 | 15 3 | 4 5 0.35 4 | 5 4 0.35 5 | 4 7 0.37 6 | 5 7 0.28 7 | 7 5 0.28 8 | 5 1 0.32 9 | 0 4 0.38 10 | 0 2 0.26 11 | 7 3 0.39 12 | 1 3 0.29 13 | 2 7 0.34 14 | 6 2 0.40 15 | 3 6 0.52 16 | 6 0 0.58 17 | 6 4 0.93 18 | -------------------------------------------------------------------------------- /graphs/graph/testdata/routes.txt: -------------------------------------------------------------------------------- 1 | JFK MCO 2 | ORD DEN 3 | ORD HOU 4 | DFW PHX 5 | JFK ATL 6 | ORD DFW 7 | ORD PHX 8 | ATL HOU 9 | DEN PHX 10 | PHX LAX 11 | JFK ORD 12 | DEN LAS 13 | DFW HOU 14 | ORD ATL 15 | LAS LAX 16 | ATL MCO 17 | HOU MCO 18 | LAS PHX 19 | -------------------------------------------------------------------------------- /graphs/digraph/testdata/routes.txt: -------------------------------------------------------------------------------- 1 | JFK MCO 2 | ORD DEN 3 | ORD HOU 4 | DFW PHX 5 | JFK ATL 6 | ORD DFW 7 | ORD PHX 8 | ATL HOU 9 | DEN PHX 10 | PHX LAX 11 | JFK ORD 12 | DEN LAS 13 | DFW HOU 14 | ORD ATL 15 | LAS LAX 16 | ATL MCO 17 | HOU MCO 18 | LAS PHX 19 | -------------------------------------------------------------------------------- /graphs/mst/testdata/tinyEWG.txt: -------------------------------------------------------------------------------- 1 | 8 2 | 16 3 | 4 5 0.35 4 | 4 7 0.37 5 | 5 7 0.28 6 | 0 7 0.16 7 | 1 5 0.32 8 | 0 4 0.38 9 | 2 3 0.17 10 | 1 7 0.19 11 | 0 2 0.26 12 | 1 2 0.36 13 | 1 3 0.29 14 | 2 7 0.34 15 | 6 2 0.40 16 | 3 6 0.52 17 | 6 0 0.58 18 | 6 4 0.93 19 | -------------------------------------------------------------------------------- /graphs/sp/testdata/tinyEWDn.txt: -------------------------------------------------------------------------------- 1 | 8 2 | 15 3 | 4 5 0.35 4 | 5 4 0.35 5 | 4 7 0.37 6 | 5 7 0.28 7 | 7 5 0.28 8 | 5 1 0.32 9 | 0 4 0.38 10 | 0 2 0.26 11 | 7 3 0.39 12 | 1 3 0.29 13 | 2 7 0.34 14 | 6 2 -1.20 15 | 3 6 0.52 16 | 6 0 -1.40 17 | 6 4 -1.25 18 | -------------------------------------------------------------------------------- /graphs/sp/testdata/tinyEWDnc.txt: -------------------------------------------------------------------------------- 1 | 8 2 | 15 3 | 4 5 0.35 4 | 5 4 -0.66 5 | 4 7 0.37 6 | 5 7 0.28 7 | 7 5 0.28 8 | 5 1 0.32 9 | 0 4 0.38 10 | 0 2 0.26 11 | 7 3 0.39 12 | 1 3 0.29 13 | 2 7 0.34 14 | 6 2 0.40 15 | 3 6 0.52 16 | 6 0 0.58 17 | 6 4 0.93 18 | -------------------------------------------------------------------------------- /graphs/digraph/testdata/tinyDG.txt: -------------------------------------------------------------------------------- 1 | 13 2 | 22 3 | 4 2 4 | 2 3 5 | 3 2 6 | 6 0 7 | 0 1 8 | 2 0 9 | 11 12 10 | 12 9 11 | 9 10 12 | 9 11 13 | 7 9 14 | 10 12 15 | 11 4 16 | 4 3 17 | 3 5 18 | 6 8 19 | 8 6 20 | 5 4 21 | 0 5 22 | 6 4 23 | 6 9 24 | 7 6 25 | -------------------------------------------------------------------------------- /cmd/fund/doubling/doubling_ratio.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func doublingRatio() { 8 | prev := timeTrial(125) 9 | for n := 250; true; n += n { 10 | time := timeTrial(n) 11 | fmt.Printf("%7d %7.1f %5.1f\n", n, time, time/prev) 12 | prev = time 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /fund/example_evaluate_test.go: -------------------------------------------------------------------------------- 1 | package fund_test 2 | 3 | import ( 4 | "fmt" 5 | "github.com/youngzhu/algs4-go/fund" 6 | ) 7 | 8 | func ExampleEvaluate() { 9 | exp := "( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )" 10 | 11 | fmt.Printf("%.1f", fund.Evaluate(exp)) 12 | 13 | // Output: 14 | // 101.0 15 | } -------------------------------------------------------------------------------- /searching/testdata/tinyTale.txt: -------------------------------------------------------------------------------- 1 | it was the best of times it was the worst of times 2 | it was the age of wisdom it was the age of foolishness 3 | it was the epoch of belief it was the epoch of incredulity 4 | it was the season of light it was the season of darkness 5 | it was the spring of hope it was the winter of despair 6 | -------------------------------------------------------------------------------- /context/suffix/testdata/tinyTale.txt: -------------------------------------------------------------------------------- 1 | it was the best of times it was the worst of times 2 | it was the age of wisdom it was the age of foolishness 3 | it was the epoch of belief it was the epoch of incredulity 4 | it was the season of light it was the season of darkness 5 | it was the spring of hope it was the winter of despair 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | -------------------------------------------------------------------------------- /cmd/fund/doubling/doubling_tester.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // Generates a sequence of random input arrays, doubling the array size 8 | // at each step, and prints the running times of ThreeSumCount for each input size. 9 | func doublingTest() { 10 | for n := 250; true; n += n { 11 | time := timeTrial(n) 12 | fmt.Printf("%7d %7.1f\n", n, time) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /fund/uf/union_find.go: -------------------------------------------------------------------------------- 1 | package uf 2 | 3 | type UnionFind interface { 4 | // Union add connection between p and q 5 | Union(p, q int) 6 | 7 | // Find returns component identifier for p (o to n-1) 8 | Find(p int) int 9 | 10 | // Connected returns true if p and q are in the same component 11 | Connected(p, q int) bool 12 | 13 | // Count returns Number of components 14 | Count() int 15 | } 16 | -------------------------------------------------------------------------------- /fund/linked_list.go: -------------------------------------------------------------------------------- 1 | package fund 2 | 3 | // Linked List. 4 | // A linked list is a recursive data structure that is either empty (nil) or 5 | // a reference to a node having an item and a reference to a linked list. 6 | 7 | type Item interface{} 8 | 9 | type Node struct { 10 | item Item 11 | next *Node 12 | } 13 | 14 | func newNode(item Item, next *Node) *Node { 15 | return &Node{item, next} 16 | } 17 | -------------------------------------------------------------------------------- /testutil/example_stopwatch_test.go: -------------------------------------------------------------------------------- 1 | package testutil_test 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/youngzhu/algs4-go/testutil" 8 | ) 9 | 10 | func ExampleStopwatch() { 11 | timer := testutil.NewStopwatch() 12 | time.Sleep(5 * time.Second) 13 | elapsedTime := timer.ElapsedTime() 14 | fmt.Printf("elapsed %.0f+ seconds", elapsedTime) 15 | 16 | // Output: 17 | // elapsed 5+ seconds 18 | 19 | } 20 | -------------------------------------------------------------------------------- /graphs/sp/sp.go: -------------------------------------------------------------------------------- 1 | package sp 2 | 3 | import "github.com/youngzhu/algs4-go/graphs" 4 | 5 | // Shortest paths. 6 | // An edge-weighted digraph is a digraph where we associate weights or costs 7 | // with each edge. A shortest path from vertex s to vertex t is a directed 8 | // path from s to t with the property that no other such path has a lower weight. 9 | 10 | type ShortestPaths interface { 11 | graphs.Paths 12 | 13 | DistTo(v int) float64 14 | } -------------------------------------------------------------------------------- /graphs/digraph/testdata/jobs.txt: -------------------------------------------------------------------------------- 1 | Algorithms/Theoretical CS/Databases/Scientific Computing 2 | Introduction to CS/Advanced Programming/Algorithms 3 | Advanced Programming/Scientific Computing 4 | Scientific Computing/Computational Biology 5 | Theoretical CS/Computational Biology/Artificial Intelligence 6 | Linear Algebra/Theoretical CS 7 | Calculus/Linear Algebra 8 | Artificial Intelligence/Neural Networks/Robotics/Machine Learning 9 | Machine Learning/Neural Networks -------------------------------------------------------------------------------- /graphs/mst/prim_mst.go: -------------------------------------------------------------------------------- 1 | package mst 2 | 3 | // Proposition. 4 | // Prim's algorithm computes the MST of any connected edge-weighted graph. 5 | // The lazy version of Prim's algorithm uses space proportional to E and time 6 | // proportional to ElogE (in the worst case) to compute the MST of a connected 7 | // edge-weighted graph with E edges and V vertices. 8 | // The eager version uses space proportional to V and time proportional to 9 | // ElogV (in the worst case). -------------------------------------------------------------------------------- /testutil/stopwatch.go: -------------------------------------------------------------------------------- 1 | package testutil 2 | 3 | import "time" 4 | 5 | // Stopwatch A utility to measure the running time (wall clock) of a program 6 | type Stopwatch struct { 7 | start time.Time 8 | } 9 | 10 | func NewStopwatch() Stopwatch { 11 | return Stopwatch{time.Now()} 12 | } 13 | 14 | // ElapsedTime returns the elapsed time (in seconds) since the stopwatch was created 15 | func (s Stopwatch) ElapsedTime() float64 { 16 | now := time.Now() 17 | dt := now.Sub(s.start) 18 | return float64(dt.Milliseconds()) / 1000 19 | } 20 | -------------------------------------------------------------------------------- /fund/xsum/xsum.go: -------------------------------------------------------------------------------- 1 | package xsum 2 | 3 | import ( 4 | "github.com/youngzhu/algs4-go/fund" 5 | "github.com/youngzhu/algs4-go/sorting" 6 | ) 7 | 8 | var ( 9 | sorter sorting.Sorter = sorting.Quick{} 10 | 11 | // fast way 12 | binarySearch = fund.NewBinarySearch() 13 | ) 14 | 15 | // returns true if the sorted array a[] 16 | // contains any duplicated integers 17 | func containsDuplicates(a []int) bool { 18 | for i := 1; i < len(a); i++ { 19 | if a[i] == a[i-1] { 20 | return true 21 | } 22 | } 23 | 24 | return false 25 | } 26 | 27 | // 28 | -------------------------------------------------------------------------------- /sorting/pq/testdata/tinyBatch.txt: -------------------------------------------------------------------------------- 1 | Turing 6/17/1990 644.08 2 | vonNeumann 3/26/2002 4121.85 3 | Dijkstra 8/22/2007 2678.40 4 | vonNeumann 1/11/1999 4409.74 5 | Dijkstra 11/18/1995 837.42 6 | Hoare 5/10/1993 3229.27 7 | vonNeumann 2/12/1994 4732.35 8 | Hoare 8/18/1992 4381.21 9 | Turing 1/11/2002 66.10 10 | Thompson 2/27/2000 4747.08 11 | Turing 2/11/1991 2156.86 12 | Hoare 8/12/2003 1025.70 13 | vonNeumann 10/13/1993 2520.97 14 | Dijkstra 9/10/2000 708.95 15 | Turing 10/12/1993 3532.36 16 | Hoare 2/10/2005 4050.20 -------------------------------------------------------------------------------- /strings/search/search.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | // Substring Search. 4 | 5 | // Rabin-Karp randomized fingerprint algorithm 6 | func RabinKarpSearch(pattern, txt string) int { 7 | search := NewRabinKarp(pattern) 8 | return search.Search(txt) 9 | } 10 | 11 | // Knuth-Morris-Pratt algorithm 12 | func KMPSearch(pattern, txt string) int { 13 | search := NewKMP(pattern) 14 | return search.Search(txt) 15 | } 16 | 17 | // The bad-character rule part of the Boyer-Moore algorithm. 18 | func BoyerMooreSearch(pattern, txt string) int { 19 | search := NewBoyerMoore(pattern) 20 | return search.Search(txt) 21 | } 22 | -------------------------------------------------------------------------------- /fund/binary_search.go: -------------------------------------------------------------------------------- 1 | package fund 2 | 3 | type BinarySearch struct{} 4 | 5 | func NewBinarySearch() BinarySearch { 6 | return BinarySearch{} 7 | } 8 | 9 | // Index return the index of the specified key in the specified array 10 | // otherwise return -1 11 | // (the array must be sorted in ascending order.) 12 | func (bs BinarySearch) Index(a []int, key int) int { 13 | lo, hi := 0, len(a)-1 14 | 15 | for lo <= hi { 16 | mid := lo + (hi-lo)/2 17 | if key < a[mid] { 18 | hi = mid - 1 19 | } else if key > a[mid] { 20 | lo = mid + 1 21 | } else { 22 | return mid 23 | } 24 | } 25 | 26 | return -1 27 | } 28 | -------------------------------------------------------------------------------- /searching/symbol_table.go: -------------------------------------------------------------------------------- 1 | package searching 2 | 3 | // SymbolTable (ST) 4 | // The primary purpose of a symbol table is to associate a value with a key. 5 | // The client can insert key-value pairs into the symbol table with the expectation 6 | // of later being able to search for the value associated with a given key. 7 | type SymbolTable interface { 8 | Put(key STKey, value STValue) 9 | Get(key STKey) STValue 10 | Delete(key STKey) 11 | Contains(key STKey) bool 12 | Keys() []STKey 13 | } 14 | 15 | // STKey the key in ST 16 | type STKey interface{} 17 | 18 | // STValue the value in ST 19 | type STValue interface{} 20 | -------------------------------------------------------------------------------- /strings/regexp/example_test.go: -------------------------------------------------------------------------------- 1 | package regexp_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/youngzhu/algs4-go/strings/regexp" 7 | ) 8 | 9 | var testCases = []struct { 10 | regExp, text string 11 | }{ 12 | {"(A*B|AC)D", "AAAABD"}, 13 | {"(A*B|AC)D", "AAAAC"}, 14 | {"(a|(bc)*d)*", "abcbcd"}, 15 | {"(a|(bc)*d)*", "abcbcbcdaaaabcbcdaaaddd"}, 16 | } 17 | 18 | func ExampleNFA() { 19 | 20 | for _, tc := range testCases { 21 | nfa := regexp.NewNFA(tc.regExp) 22 | result := nfa.Recognizes(tc.text) 23 | fmt.Println(result) 24 | } 25 | 26 | // Output: 27 | // true 28 | // false 29 | // true 30 | // true 31 | } 32 | -------------------------------------------------------------------------------- /fund/xsum/bench_test.go: -------------------------------------------------------------------------------- 1 | package xsum_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/youngzhu/algs4-go/fund/xsum" 7 | "github.com/youngzhu/algs4-go/testutil" 8 | ) 9 | 10 | // go test -v -run="none" -bench="." -benchtime="3s" 11 | 12 | var a = testutil.NewIn("testdata/1Kints.txt").ReadAllInts() 13 | 14 | func BenchmarkTwoSumCount(b *testing.B) { 15 | 16 | b.ReportAllocs() 17 | b.ResetTimer() 18 | 19 | for i := 0; i < b.N; i++ { 20 | TwoSumCount(a[0:]) 21 | } 22 | } 23 | 24 | func BenchmarkTwoSumCountFast(b *testing.B) { 25 | 26 | b.ReportAllocs() 27 | b.ResetTimer() 28 | 29 | for i := 0; i < b.N; i++ { 30 | TwoSumCountFast(a[0:]) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | workflow_dispatch: 10 | 11 | jobs: 12 | 13 | test: 14 | strategy: 15 | matrix: 16 | go-version: [1.16.x, 1.17.x] 17 | os: [ubuntu-latest, macos-latest, windows-latest] 18 | runs-on: ${{ matrix.os }} 19 | 20 | steps: 21 | - uses: actions/checkout@v3 22 | 23 | - name: Set up Go 24 | uses: actions/setup-go@v3 25 | with: 26 | go-version: ${{ matrix.go-version }} 27 | 28 | - name: Build 29 | run: go build -v ./... 30 | 31 | - name: Test 32 | run: go test ./... -v -cover 33 | -------------------------------------------------------------------------------- /fund/xsum/two_sum.go: -------------------------------------------------------------------------------- 1 | package xsum 2 | 3 | // TwoSumCount returns the number of distinct pairs (i, j) 4 | // such that a[i]+a[j]=0 5 | func TwoSumCount(a []int) int { 6 | n := len(a) 7 | count := 0 8 | 9 | for i := 0; i < n; i++ { 10 | for j := i + 1; j < n; j++ { 11 | if a[i]+a[j] == 0 { 12 | count++ 13 | } 14 | } 15 | } 16 | 17 | return count 18 | } 19 | 20 | func TwoSumCountFast(a []int) int { 21 | 22 | sorter.SortInts(a) 23 | 24 | if containsDuplicates(a) { 25 | panic("contains duplicate integers") 26 | } 27 | 28 | count := 0 29 | 30 | n := len(a) 31 | for i := 0; i < n; i++ { 32 | if j := binarySearch.Index(a, -a[i]); j > i { 33 | count++ 34 | } 35 | } 36 | 37 | return count 38 | } 39 | -------------------------------------------------------------------------------- /graphs/paths.go: -------------------------------------------------------------------------------- 1 | package graphs 2 | 3 | import ( 4 | "github.com/youngzhu/algs4-go/fund" 5 | "github.com/youngzhu/algs4-go/sorting/pq" 6 | ) 7 | 8 | // source vertex s 9 | type Paths interface { 10 | // Is there a path from s to v 11 | HasPathTo(v int) bool 12 | // Path from s to v 13 | PathTo(v int) fund.Iterator 14 | } 15 | 16 | type Distance float64 17 | 18 | func (d Distance) CompareTo(x pq.Item) int { 19 | xx := x.(Distance) 20 | if d < xx { 21 | return -1 22 | } else if d > xx { 23 | return 1 24 | } else { 25 | return 0 26 | } 27 | } 28 | 29 | const ( 30 | DistanceInfinity = 10000.0 31 | DistanceNegativeInfinity = -10000.0 32 | 33 | // the same 34 | // DistanceZero = Distance(0.0) 35 | DistanceZero Distance = 0.0 36 | ) -------------------------------------------------------------------------------- /strings/sort/sort.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | const cutoff = 15 // cutoff to insertion sort 4 | 5 | // insertion sort a[lo..hi], starting at dth character 6 | func insertion(a []string, lo, hi, d int) { 7 | for i := lo; i <= hi; i++ { 8 | for j := i; j > lo && less(a[j], a[j-1], d); j-- { 9 | a[j], a[j-1] = a[j-1], a[j] 10 | } 11 | } 12 | } 13 | 14 | // is s1 less than s2, starting at dth character 15 | func less(s1, s2 string, d int) bool { 16 | len1, len2 := len(s1), len(s2) 17 | for i := d; i < min(len1, len2); i++ { 18 | if s1[i] < s2[i] { 19 | return true 20 | } 21 | if s1[i] > s2[i] { 22 | return false 23 | } 24 | } 25 | return len1 < len2 26 | } 27 | 28 | func min(x, y int) int { 29 | if x < y { 30 | return x 31 | } 32 | return y 33 | } 34 | -------------------------------------------------------------------------------- /graphs/digraph/directed_edge.go: -------------------------------------------------------------------------------- 1 | package digraph 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type DirectedEdge struct { 8 | v, w int 9 | weight float64 10 | } 11 | 12 | func NewDirectedEdge(v, w int, weight float64) *DirectedEdge { 13 | if v < 0 || w < 0 { 14 | panic("vertex index must be a non-negative integer") 15 | } 16 | 17 | return &DirectedEdge{v, w, weight} 18 | } 19 | 20 | // Returns the tail vertex of the directed edge 21 | func (e *DirectedEdge) From() int { 22 | return e.v 23 | } 24 | 25 | // Returns the head vertex of the directed edge 26 | func (e *DirectedEdge) To() int { 27 | return e.w 28 | } 29 | 30 | func (e *DirectedEdge) Weight() float64 { 31 | return e.weight 32 | } 33 | 34 | func (e *DirectedEdge) String() string { 35 | return fmt.Sprintf("%d->%d %5.2f", e.v, e.w, e.weight) 36 | } -------------------------------------------------------------------------------- /sorting/heap_test.go: -------------------------------------------------------------------------------- 1 | package sorting_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/youngzhu/algs4-go/sorting" 7 | ) 8 | 9 | func TestHeapsortInts(t *testing.T) { 10 | data := ints 11 | x := IntSortSlice(data[0:]) 12 | Heapsort(x) 13 | if !IsSorted(x) { 14 | t.Errorf("sorting %v", ints) 15 | t.Errorf(" got %v", data) 16 | } 17 | } 18 | 19 | func TestHeapsortFloat64s(t *testing.T) { 20 | data := float64s 21 | x := Float64SortSlice(data[0:]) 22 | Heapsort(x) 23 | if !IsSorted(x) { 24 | t.Errorf("sorting %v", float64s) 25 | t.Errorf(" got %v", data) 26 | } 27 | } 28 | 29 | func TestHeapsortStrings(t *testing.T) { 30 | data := strings 31 | x := StringSortSlice(data[0:]) 32 | Heapsort(x) 33 | if !IsSorted(x) { 34 | t.Errorf("sorting %v", strings) 35 | t.Errorf(" got %v", data) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /sorting/quick_test.go: -------------------------------------------------------------------------------- 1 | package sorting_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/youngzhu/algs4-go/sorting" 7 | ) 8 | 9 | func TestQuicksortInts(t *testing.T) { 10 | data := ints 11 | x := IntSortSlice(data[0:]) 12 | Quicksort(x) 13 | if !IsSorted(x) { 14 | t.Errorf("sorting %v", ints) 15 | t.Errorf(" got %v", data) 16 | } 17 | } 18 | 19 | func TestQuicksortFloat64s(t *testing.T) { 20 | data := float64s 21 | x := Float64SortSlice(data[0:]) 22 | Quicksort(x) 23 | if !IsSorted(x) { 24 | t.Errorf("sorting %v", float64s) 25 | t.Errorf(" got %v", data) 26 | } 27 | } 28 | 29 | func TestQuicksortStrings(t *testing.T) { 30 | data := strings 31 | x := StringSortSlice(data[0:]) 32 | Quicksort(x) 33 | if !IsSorted(x) { 34 | t.Errorf("sorting %v", strings) 35 | t.Errorf(" got %v", data) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /sorting/shell_test.go: -------------------------------------------------------------------------------- 1 | package sorting_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/youngzhu/algs4-go/sorting" 7 | ) 8 | 9 | func TestShellsortInts(t *testing.T) { 10 | data := ints 11 | x := IntSortSlice(data[0:]) 12 | ShellSort(x) 13 | if !IsSorted(x) { 14 | t.Errorf("sorting %v", ints) 15 | t.Errorf(" got %v", data) 16 | } 17 | } 18 | 19 | func TestShellsortFloat64s(t *testing.T) { 20 | data := float64s 21 | x := Float64SortSlice(data[0:]) 22 | ShellSort(x) 23 | if !IsSorted(x) { 24 | t.Errorf("sorting %v", float64s) 25 | t.Errorf(" got %v", data) 26 | } 27 | } 28 | 29 | func TestShellsortStrings(t *testing.T) { 30 | data := strings 31 | x := StringSortSlice(data[0:]) 32 | ShellSort(x) 33 | if !IsSorted(x) { 34 | t.Errorf("sorting %v", strings) 35 | t.Errorf(" got %v", data) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /sorting/sorting_test.go: -------------------------------------------------------------------------------- 1 | package sorting_test 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | 7 | . "github.com/youngzhu/algs4-go/sorting" 8 | ) 9 | 10 | // test data 11 | // array 12 | var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586} 13 | var float64s = [...]float64{74.3, 59.0, math.Inf(1), 238.2, -784.0, 2.3, math.NaN(), math.NaN(), math.Inf(-1), 9845.768, -959.7485, 905, 7.8, 7.8} 14 | var strings = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"} 15 | 16 | func TestIsSortedInt(t *testing.T) { 17 | sorted := IntSortSlice([]int{-99, 0, 99, 100}) 18 | if !IsSorted(sorted) { 19 | t.Errorf("excepted true, got false") 20 | } 21 | 22 | unsorted := IntSortSlice([]int{1000, 88888, -1, 9, 66}) 23 | if IsSorted(unsorted) { 24 | t.Errorf("excepted false, got true") 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sorting/mergex_test.go: -------------------------------------------------------------------------------- 1 | package sorting_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/youngzhu/algs4-go/sorting" 7 | ) 8 | 9 | func TestMergesortXInts(t *testing.T) { 10 | data := ints 11 | x := IntSortSlice(data[0:]) 12 | MergesortX(x) 13 | if !IsSorted(x) { 14 | t.Errorf("sorting %v", ints) 15 | t.Errorf(" got %v", data) 16 | } 17 | } 18 | 19 | func TestMergesortXFloat64s(t *testing.T) { 20 | data := float64s 21 | x := Float64SortSlice(data[0:]) 22 | MergesortX(x) 23 | if !IsSorted(x) { 24 | t.Errorf("sorting %v", float64s) 25 | t.Errorf(" got %v", data) 26 | } 27 | } 28 | 29 | func TestMergesortXStrings(t *testing.T) { 30 | data := strings 31 | x := StringSortSlice(data[0:]) 32 | MergesortX(x) 33 | if !IsSorted(x) { 34 | t.Errorf("sorting %v", strings) 35 | t.Errorf(" got %v", data) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /sorting/merge_bu_test.go: -------------------------------------------------------------------------------- 1 | package sorting_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/youngzhu/algs4-go/sorting" 7 | ) 8 | 9 | func TestMergesortBUInts(t *testing.T) { 10 | data := ints 11 | x := IntSortSlice(data[0:]) 12 | MergesortBU(x) 13 | if !IsSorted(x) { 14 | t.Errorf("sorting %v", ints) 15 | t.Errorf(" got %v", data) 16 | } 17 | } 18 | 19 | func TestMergesortBUFloat64s(t *testing.T) { 20 | data := float64s 21 | x := Float64SortSlice(data[0:]) 22 | MergesortBU(x) 23 | if !IsSorted(x) { 24 | t.Errorf("sorting %v", float64s) 25 | t.Errorf(" got %v", data) 26 | } 27 | } 28 | 29 | func TestMergesortBUStrings(t *testing.T) { 30 | data := strings 31 | x := StringSortSlice(data[0:]) 32 | MergesortBU(x) 33 | if !IsSorted(x) { 34 | t.Errorf("sorting %v", strings) 35 | t.Errorf(" got %v", data) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /strings/search/brute_force.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | // Brute force string search. 4 | // Return offset of first match or -1 if no match 5 | func BruteForceSearch1(pattern, text string) int { 6 | m, n := len(pattern), len(text) 7 | 8 | for i := 0; i <= n-m; i++ { 9 | j := 0 10 | for ; j < m; j++ { 11 | if text[i+j] != pattern[j] { 12 | break 13 | } 14 | } 15 | if j == m { 16 | return i // found at offset i 17 | } 18 | } 19 | 20 | return -1 // not found 21 | } 22 | 23 | func BruteForceSearch2(pattern, text string) int { 24 | m, n := len(pattern), len(text) 25 | 26 | i, j := 0, 0 27 | for ; i < n && j < m; i++ { 28 | if text[i] == pattern[j] { 29 | j++ 30 | } else { 31 | i -= j 32 | j = 0 33 | } 34 | } 35 | 36 | if j == m { 37 | return i - m // found 38 | } else { 39 | return -1 // not found 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /sorting/insertion_test.go: -------------------------------------------------------------------------------- 1 | package sorting_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/youngzhu/algs4-go/sorting" 7 | ) 8 | 9 | func TestInsertionSortInts(t *testing.T) { 10 | data := ints 11 | x := IntSortSlice(data[0:]) 12 | InsertionSort(x) 13 | if !IsSorted(x) { 14 | t.Errorf("sorting %v", ints) 15 | t.Errorf(" got %v", data) 16 | } 17 | } 18 | 19 | func TestInsertionSortFloat64s(t *testing.T) { 20 | data := float64s 21 | x := Float64SortSlice(data[0:]) 22 | InsertionSort(x) 23 | if !IsSorted(x) { 24 | t.Errorf("sorting %v", float64s) 25 | t.Errorf(" got %v", data) 26 | } 27 | } 28 | 29 | func TestInsertionSortStrings(t *testing.T) { 30 | data := strings 31 | x := StringSortSlice(data[0:]) 32 | InsertionSort(x) 33 | if !IsSorted(x) { 34 | t.Errorf("sorting %v", strings) 35 | t.Errorf(" got %v", data) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /sorting/quick_3way_test.go: -------------------------------------------------------------------------------- 1 | package sorting_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/youngzhu/algs4-go/sorting" 7 | ) 8 | 9 | func TestQuicksort3wayInts(t *testing.T) { 10 | data := ints 11 | x := IntSortSlice(data[0:]) 12 | Quicksort3way(x) 13 | if !IsSorted(x) { 14 | t.Errorf("sorting %v", ints) 15 | t.Errorf(" got %v", data) 16 | } 17 | } 18 | 19 | func TestQuicksort3wayFloat64s(t *testing.T) { 20 | data := float64s 21 | x := Float64SortSlice(data[0:]) 22 | Quicksort3way(x) 23 | if !IsSorted(x) { 24 | t.Errorf("sorting %v", float64s) 25 | t.Errorf(" got %v", data) 26 | } 27 | } 28 | 29 | func TestQuicksort3wayStrings(t *testing.T) { 30 | data := strings 31 | x := StringSortSlice(data[0:]) 32 | Quicksort3way(x) 33 | if !IsSorted(x) { 34 | t.Errorf("sorting %v", strings) 35 | t.Errorf(" got %v", data) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /sorting/selection_test.go: -------------------------------------------------------------------------------- 1 | package sorting_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/youngzhu/algs4-go/sorting" 7 | ) 8 | 9 | func TestSelectionSortInts(t *testing.T) { 10 | data := ints 11 | x := IntSortSlice(data[0:]) 12 | SelectionSort(x) 13 | if !IsSorted(x) { 14 | t.Errorf("sorting %v", ints) 15 | t.Errorf(" got %v", data) 16 | } 17 | } 18 | 19 | func TestSelectionSortFloat64s(t *testing.T) { 20 | data := float64s 21 | x := Float64SortSlice(data[0:]) 22 | SelectionSort(x) 23 | if !IsSorted(x) { 24 | t.Errorf("sorting %v", float64s) 25 | t.Errorf(" got %v", data) 26 | } 27 | } 28 | 29 | func TestSelectionSortStrings(t *testing.T) { 30 | data := strings 31 | x := StringSortSlice(data[0:]) 32 | SelectionSort(x) 33 | if !IsSorted(x) { 34 | t.Errorf("sorting %v", strings) 35 | t.Errorf(" got %v", data) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /testutil/random.go: -------------------------------------------------------------------------------- 1 | package testutil 2 | 3 | import ( 4 | "math/rand" 5 | "time" 6 | ) 7 | 8 | type Random struct { 9 | *rand.Rand 10 | } 11 | 12 | var _r *Random 13 | 14 | func init() { 15 | _r = NewRandom() 16 | } 17 | 18 | func NewRandom() *Random { 19 | seed := time.Now().UnixNano() 20 | r := rand.New(rand.NewSource(seed)) 21 | return &Random{r} 22 | } 23 | 24 | // UniformIntRange Returns a random integer uniformly in [a, b) 25 | func (r Random) UniformIntRange(a, b int) int { 26 | if b <= a { 27 | panic("invalid range") 28 | } 29 | 30 | return a + r.UniformIntN(b-a) 31 | } 32 | func UniformIntRange(a, b int) int { 33 | return _r.UniformIntRange(a, b) 34 | } 35 | 36 | // UniformIntN Returns a random integer uniformly in [0, n) 37 | func (r Random) UniformIntN(n int) int { 38 | return r.Intn(n) 39 | } 40 | func UniformIntN(n int) int { 41 | return _r.UniformIntN(n) 42 | } 43 | -------------------------------------------------------------------------------- /fund/xsum/three_sum.go: -------------------------------------------------------------------------------- 1 | package xsum 2 | 3 | // Counts the number of triples in an array of N integers that sums to 0 4 | 5 | // Returns the number of triples (i, j, k) with i j { 38 | count++ 39 | } 40 | } 41 | } 42 | 43 | return count 44 | } 45 | -------------------------------------------------------------------------------- /sorting/merge_test.go: -------------------------------------------------------------------------------- 1 | package sorting_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/youngzhu/algs4-go/sorting" 7 | ) 8 | 9 | var intsX2 = [...]int{74, 59, 238, -784, 98, 959, 999, 1000, 6666, 2333, 9999} 10 | 11 | func TestMergesortInts(t *testing.T) { 12 | data := intsX2 13 | x := IntSortSlice(data[0:]) 14 | Mergesort(x) 15 | if !IsSorted(x) { 16 | t.Errorf("sorting %v", ints) 17 | t.Errorf(" got %v", data) 18 | } 19 | } 20 | 21 | func TestMergesortFloat64s(t *testing.T) { 22 | data := float64s 23 | x := Float64SortSlice(data[0:]) 24 | Mergesort(x) 25 | if !IsSorted(x) { 26 | t.Errorf("sorting %v", float64s) 27 | t.Errorf(" got %v", data) 28 | } 29 | } 30 | 31 | func TestMergesortStrings(t *testing.T) { 32 | data := strings 33 | x := StringSortSlice(data[0:]) 34 | Mergesort(x) 35 | if !IsSorted(x) { 36 | t.Errorf("sorting %v", strings) 37 | t.Errorf(" got %v", data) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /testutil/example_random_test.go: -------------------------------------------------------------------------------- 1 | package testutil_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/youngzhu/algs4-go/testutil" 7 | ) 8 | 9 | func ExampleRandom_UniformIntN() { 10 | r := testutil.NewRandom() 11 | 12 | // Seeding with the same value results in the same random 13 | // sequence each run. 14 | r.Seed(100) 15 | 16 | fmt.Println(r.UniformIntN(100)) 17 | fmt.Println(r.UniformIntN(100)) 18 | fmt.Println(r.UniformIntN(100)) 19 | 20 | // Output: 21 | // 83 22 | // 68 23 | // 80 24 | } 25 | 26 | func ExampleRandom_UniformIntRange() { 27 | r := testutil.NewRandom() 28 | 29 | // Seeding with the same value results in the same random 30 | // sequence each run. 31 | r.Seed(9999) 32 | 33 | a, b := -10000, 10000 34 | 35 | fmt.Println(r.UniformIntRange(a, b)) 36 | fmt.Println(r.UniformIntRange(a, b)) 37 | fmt.Println(r.UniformIntRange(a, b)) 38 | 39 | // Output: 40 | // -1219 41 | // 8260 42 | // -8752 43 | } 44 | -------------------------------------------------------------------------------- /cmd/fund/doubling/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | 6 | "github.com/youngzhu/algs4-go/fund/xsum" 7 | "github.com/youngzhu/algs4-go/testutil" 8 | ) 9 | 10 | var ( 11 | rand testutil.Random 12 | ratio = flag.Bool("r", false, "doubling ratio test") 13 | ) 14 | 15 | func init() { 16 | rand = *testutil.NewRandom() 17 | } 18 | 19 | func main() { 20 | flag.Parse() 21 | 22 | if *ratio { 23 | doublingRatio() 24 | } else { 25 | doublingTest() 26 | } 27 | } 28 | 29 | const ( 30 | min = -1000000 31 | max = 1000000 32 | ) 33 | 34 | // Returns the amount of time to call ThreeSumCount() with n random 35 | // 6-digit integers 36 | func timeTrial(n int) float64 { 37 | a := make([]int, n) 38 | for i := 0; i < n; i++ { 39 | a[i] = rand.UniformIntRange(min, max) 40 | } 41 | timer := testutil.NewStopwatch() 42 | 43 | xsum.ThreeSumCount(a) 44 | 45 | // xsum.TwoSumCount(a) 46 | // xsum.TwoSumCountFast(a) 47 | 48 | return timer.ElapsedTime() 49 | } 50 | -------------------------------------------------------------------------------- /sorting/pq/binary_heap_based0.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | // binary heap using 0-based indexing 4 | type BinaryHeapBased0 struct{} 5 | 6 | // factory method 7 | func NewBinaryHeapBased0() BinaryHeapBased0 { 8 | return BinaryHeapBased0{} 9 | } 10 | 11 | // 0-based 12 | func (bh BinaryHeapBased0) GetLeftChildIndex(p, n int) int { 13 | leftChild := 2*p + 1 14 | if leftChild >= n { 15 | return -1 // no valid left child 16 | } 17 | 18 | return leftChild 19 | } 20 | 21 | func (bh BinaryHeapBased0) GetRightChildIndex(p, n int) int { 22 | rightChild := 2*p + 2 23 | if rightChild >= n { 24 | return -1 // no valid right child 25 | } 26 | 27 | return rightChild 28 | } 29 | 30 | func (bh BinaryHeapBased0) GetParentIndex(c, n int) int { 31 | if c < 0 || c > n { 32 | return -1 33 | } 34 | 35 | return (c - 1) / 2 36 | } 37 | 38 | func (bh BinaryHeapBased0) GetRootIndex() int { 39 | return 0 40 | } 41 | 42 | func (bh BinaryHeapBased0) GetLastLeafIndex(n int) int { 43 | return n - 1 44 | } 45 | -------------------------------------------------------------------------------- /sorting/insertion.go: -------------------------------------------------------------------------------- 1 | package sorting 2 | 3 | // InsertionSort 4 | // The algorithm that people often use to sort bridge hands is to consider 5 | // the cards one at a time, inserting each into its proper place among those 6 | // already considered (keeping them sorted). 7 | // In a computer implementation, we need to make space for the current item by moving 8 | // larger items one position to the right, before inserting the current item into the 9 | // vacated position 10 | func InsertionSort(x Sortable) { 11 | n := x.Len() 12 | for i := 1; i < n; i++ { 13 | // keep x[0...i] sorted 14 | for j := i; j > 0 && x.Less(j, j-1); j-- { 15 | x.Swap(j, j-1) 16 | } 17 | } 18 | } 19 | 20 | type Insertion struct{} 21 | 22 | func NewInsertion() Sorter { 23 | return Insertion{} 24 | } 25 | 26 | func (s Insertion) SortInts(x []int) { 27 | InsertionSort(IntSortSlice(x)) 28 | } 29 | func (s Insertion) SortFloat64s(x []float64) { 30 | InsertionSort(Float64SortSlice(x)) 31 | } 32 | func (s Insertion) SortStrings(x []string) { 33 | InsertionSort(StringSortSlice(x)) 34 | } 35 | -------------------------------------------------------------------------------- /sorting/selection.go: -------------------------------------------------------------------------------- 1 | package sorting 2 | 3 | // Selection Sort 4 | // First, find the smallest item int the slice, and swap it with the first entry 5 | // Then, find the next smallest item and swap it with the second entry 6 | // Continue in this way until the entire slice is sorted 7 | 8 | // This method is called selection sort because it works by repeatedly selecting 9 | // the smallest remaining items 10 | 11 | func SelectionSort(x Sortable) { 12 | n := x.Len() 13 | for i := 0; i < n; i++ { 14 | ithMin := i // the i-th smallest item's index 15 | for j := i + 1; j < n; j++ { 16 | if x.Less(j, ithMin) { 17 | ithMin = j 18 | } 19 | } 20 | x.Swap(i, ithMin) 21 | } 22 | } 23 | 24 | type Selection struct{} 25 | 26 | func NewSelection() Sorter { 27 | return Selection{} 28 | } 29 | 30 | // Implements Sorter 31 | 32 | func (s Selection) SortInts(x []int) { 33 | SelectionSort(IntSortSlice(x)) 34 | } 35 | func (s Selection) SortFloat64s(x []float64) { 36 | SelectionSort(Float64SortSlice(x)) 37 | } 38 | func (s Selection) SortStrings(x []string) { 39 | SelectionSort(StringSortSlice(x)) 40 | } 41 | -------------------------------------------------------------------------------- /strings/sort/quick_3way.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | // Quicksort sorting an array of strings using 3-way radix quicksort. 4 | func Quicksort(a []string) { 5 | // random.shuffle(a) 6 | quicksort(a, 0, len(a)-1, 0) 7 | } 8 | 9 | // 3-way string quicksort a[lo..hi] starting at dth character 10 | func quicksort(a []string, lo, hi, d int) { 11 | // cutoff to insertion sort for small subarrays 12 | if hi <= lo+cutoff { 13 | insertion(a, lo, hi, d) 14 | return 15 | } 16 | 17 | lt, gt := lo, hi 18 | v := charAt(a[lo], d) 19 | i := lo + 1 20 | for i <= gt { 21 | t := charAt(a[i], d) 22 | if t < v { 23 | a[lt], a[i] = a[i], a[lt] 24 | lt++ 25 | i++ 26 | } else if t > v { 27 | a[i], a[gt] = a[gt], a[i] 28 | gt-- 29 | } else { 30 | i++ 31 | } 32 | } 33 | 34 | // a[lo..lt-1] < v = a[lt..gt] < a[gt+1..hi] 35 | quicksort(a, lo, lt-1, d) 36 | quicksort(a, lt, gt, d+1) 37 | quicksort(a, gt+1, hi, d) 38 | } 39 | 40 | // return the dth character of s 41 | // -1 if d=len(s) 42 | func charAt(s string, d int) int { 43 | if d == len(s) { 44 | return -1 45 | } 46 | return int(s[d]) 47 | } 48 | -------------------------------------------------------------------------------- /graphs/graphs.go: -------------------------------------------------------------------------------- 1 | package graphs 2 | 3 | // Pairwise connections between items play a critical role in a vast array of 4 | // computational applications. The relationships implied by these connections 5 | // lead to a host of natural questions: Is there a way to connect one item to 6 | // another by following the connections? How many other items are connected to 7 | // a given item? What is the shortest chain of connections between this item 8 | // and this other item? 9 | // We progress through the four most important types of graph models: 10 | // 1. Undirected Graphs (Graph) introduces the graph data type, including 11 | // depth-first search and breadth-first search. 12 | // 2. Directed Graphs (Digraph) introduces the digraph data type, including 13 | // topological sort and strong components. 14 | // 3. Minimum Spanning Trees (MST) describes the minimum spanning tree problem 15 | // and two classic algorithms for solving it: Prim and Kruskal. 16 | // 4. Shortest Paths (SP) introduces the shortest path problem and two classic 17 | // algorithm for solving it: Dijkstra's algorithm and Bellman-Ford. 18 | 19 | const InfinityDistance = 10000 20 | -------------------------------------------------------------------------------- /strings/search/kmp.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | // Knuth-Morris-Pratt algorithm. 4 | type KMP struct { 5 | radix int // the radix 6 | m int // length of pattern 7 | dfa [][]int // the KMP automoton 8 | } 9 | 10 | func NewKMP(pattern string) *KMP { 11 | radix := 256 12 | m := len(pattern) 13 | 14 | // build DFA from pattern 15 | dfa := make([][]int, radix) 16 | for i := range dfa { 17 | dfa[i] = make([]int, m) 18 | } 19 | dfa[pattern[0]][0] = 1 20 | for x, j := 0, 1; j < m; j++ { 21 | for c := 0; c < radix; c++ { 22 | dfa[c][j] = dfa[c][x] // copy mismatch cases 23 | } 24 | dfa[pattern[j]][j] = j + 1 // set match case 25 | x = dfa[pattern[j]][x] // update restart state 26 | } 27 | 28 | return &KMP{radix, m, dfa} 29 | } 30 | 31 | // Returns the index of the first occurrence of the pattern sting 32 | // in the text string. 33 | // If no such match, renturn -1 34 | func (s *KMP) Search(txt string) int { 35 | // simulate operation of DFA on text 36 | n := len(txt) 37 | i, j := 0, 0 38 | for ; i < n && j < s.m; i++ { 39 | j = s.dfa[txt[i]][j] 40 | } 41 | 42 | if j == s.m { 43 | return i - s.m // found 44 | } else { 45 | return -1 // not found 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /strings/sort/msd.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | import "github.com/youngzhu/algs4-go/strings" 4 | 5 | // Sort an array of strings using MSD radix sort 6 | 7 | // Rearranges the array of extended ASCII strings in ascending order 8 | func MSDSort(a []string) { 9 | n := len(a) 10 | aux := make([]string, n) 11 | sort(a, aux, 0, n-1, 0) 12 | } 13 | 14 | // sort from a[lo] to a[hi], starting at the dth character 15 | func sort(a, aux []string, lo, hi, d int) { 16 | // cutoff to insertion sort for small subarrays 17 | if hi < lo+cutoff { 18 | insertion(a, lo, hi, d) 19 | return 20 | } 21 | 22 | // compute frequency counts 23 | count := make([]int, strings.R+2) 24 | for i := lo; i <= hi; i++ { 25 | c := a[i][d] 26 | count[c+2]++ 27 | } 28 | 29 | // transform counts to indicies 30 | for r := 0; r < strings.R; r++ { 31 | count[r+1] += count[r] 32 | } 33 | 34 | // distribute 35 | for i := lo; i <= hi; i++ { 36 | c := a[i][d] 37 | aux[count[c+1]] = a[i] 38 | count[c+1]++ 39 | } 40 | 41 | // copy back 42 | for i := lo; i <= hi; i++ { 43 | a[i] = aux[i-lo] 44 | } 45 | 46 | // recursively sort for each character (excludes sentinel -1) 47 | for r := 0; r < strings.R; r++ { 48 | sort(a, aux, lo+count[r], lo+count[r+1]-1, d+1) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /sorting/pq/example_index_pq_test.go: -------------------------------------------------------------------------------- 1 | package pq_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/youngzhu/algs4-go/sorting/pq" 7 | "github.com/youngzhu/algs4-go/testutil" 8 | ) 9 | 10 | // A client that reads sorted text files, 11 | // merge them together into a sorted output 12 | 13 | func ExampleMinIndexPQ() { 14 | streams := []testutil.In{ 15 | *testutil.NewInReadWords("testdata/m1.txt"), 16 | *testutil.NewInReadWords("testdata/m2.txt"), 17 | *testutil.NewInReadWords("testdata/m3.txt"), 18 | } 19 | 20 | merge(pq.NewMinIndexPQ(len(streams)), streams) 21 | 22 | // Output: 23 | // A A B B B C D E F F G H I I J N P Q Q Z 24 | } 25 | 26 | // merge the sorted input streams 27 | func merge(ipq pq.IndexPriorityQueue, streams []testutil.In) { 28 | n := len(streams) 29 | for i := 0; i < n; i++ { 30 | if streams[i].HasNext() { 31 | item := pq.StringItem(streams[i].ReadString()) 32 | ipq.Insert(i, item) 33 | } 34 | } 35 | 36 | // extract and print min and read next from its stream 37 | for !ipq.IsEmpty() { 38 | fmt.Print(ipq.HighestPriorityItem(), " ") 39 | i := ipq.Delete() 40 | // fmt.Println(ipq) 41 | if streams[i].HasNext() { 42 | item := pq.StringItem(streams[i].ReadString()) 43 | ipq.Insert(i, item) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /graphs/mst/edge.go: -------------------------------------------------------------------------------- 1 | package mst 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/youngzhu/algs4-go/sorting/pq" 7 | ) 8 | 9 | type Edge struct { 10 | v, w int 11 | weight float64 12 | } 13 | 14 | func NewEdge(v, w int, weight float64) *Edge { 15 | if v < 0 || w < 0 { 16 | panic("vertex index must be a non-negative integer") 17 | } 18 | 19 | return &Edge{v, w, weight} 20 | } 21 | 22 | /* The Either() and Other methods are usefule for accessing the edge's vertices */ 23 | 24 | // Return either endpoint of this edge 25 | func (e *Edge) Either() int { 26 | return e.v 27 | } 28 | 29 | // Returns the endpoint of this edge that is different from the given vertex 30 | func (e *Edge) Other(vertex int) int { 31 | if vertex == e.v { 32 | return e.w 33 | } else if vertex == e.w { 34 | return e.v 35 | } else { 36 | panic("Illegal endpoint") 37 | } 38 | } 39 | 40 | func (e *Edge) Weight() float64 { 41 | return e.weight 42 | } 43 | 44 | // Returns a string representation of this edge 45 | func (e *Edge) String() string { 46 | return fmt.Sprintf("%d-%d %.5f", e.v, e.w, e.weight) 47 | } 48 | 49 | // implement pq.Item 50 | func (e *Edge) CompareTo(x pq.Item) int { 51 | ee := x.(*Edge) 52 | if e.weight < ee.weight { 53 | return -1 54 | } else if e.weight > ee.weight { 55 | return 1 56 | } else { 57 | return 0 58 | } 59 | } -------------------------------------------------------------------------------- /sorting/pq/bench_test.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // go test -v -run="none" -bench="." -benchtime="3s" 8 | 9 | var arr = []string{"S", "I", "M", "-", "P", "L", "E", "H", "-", "-", "E", "A", "P"} 10 | 11 | func testHeap(maxPQ *MaxPQ) { 12 | for _, item := range arr { 13 | if item == "-" { 14 | maxPQ.Delete() 15 | } else { 16 | maxPQ.Insert(StringItem(item)) 17 | } 18 | } 19 | } 20 | 21 | func BenchmarkMaxPQ_based0(b *testing.B) { 22 | maxPQ := newMaxPQBased0() 23 | 24 | b.ReportAllocs() 25 | b.ResetTimer() 26 | 27 | for i := 0; i < b.N; i++ { 28 | testHeap(maxPQ) 29 | } 30 | } 31 | 32 | func BenchmarkMaxPQ_based1(b *testing.B) { 33 | maxPQ := newMaxPQBased1() 34 | 35 | b.ReportAllocs() 36 | b.ResetTimer() 37 | 38 | for i := 0; i < b.N; i++ { 39 | testHeap(maxPQ) 40 | } 41 | } 42 | 43 | func BenchmarkMinPQ(b *testing.B) { 44 | maxPQ := newMaxPQBased1() 45 | 46 | b.ReportAllocs() 47 | b.ResetTimer() 48 | 49 | for i := 0; i < b.N; i++ { 50 | testHeap(maxPQ) 51 | } 52 | } 53 | 54 | func newMaxPQBased0() *MaxPQ { 55 | items := make([]Item, 1) 56 | heap := NewBinaryHeapBased0() 57 | return &MaxPQ{items, 0, heap} 58 | } 59 | func newMaxPQBased1() *MaxPQ { 60 | items := make([]Item, 1) 61 | heap := NewBinaryHeapBased1() 62 | return &MaxPQ{items, 0, heap} 63 | } 64 | -------------------------------------------------------------------------------- /fund/bag.go: -------------------------------------------------------------------------------- 1 | package fund 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | // Bags. 9 | // A bag is a collection where removing items is not supported -- its purpose 10 | // is to provide clients with the ability to collect items and then to iterate 11 | // through the collected items. 12 | 13 | // Bag implemented using a singly linked list 14 | type Bag struct { 15 | first *Node // beginning of bag 16 | size int // number of elements in bag 17 | } 18 | 19 | func NewBag() *Bag { 20 | return &Bag{} 21 | } 22 | 23 | // Add adds the item to this bag 24 | func (b *Bag) Add(item Item) { 25 | b.first = newNode(item, b.first) 26 | b.size++ 27 | } 28 | 29 | func (b *Bag) Iterator() Iterator { 30 | items := make([]interface{}, b.size) 31 | 32 | for i, cur := 0, b.first; i < b.size; i, cur = i+1, cur.next { 33 | items[i] = cur.item 34 | } 35 | 36 | return items 37 | } 38 | 39 | // IsEmpty returns true if this bag is empty 40 | func (b *Bag) IsEmpty() bool { 41 | return b.first == nil 42 | } 43 | 44 | // Size returns the number of items in this bag 45 | func (b *Bag) Size() int { 46 | return b.size 47 | } 48 | 49 | func (b *Bag) String() string { 50 | var ss []string 51 | 52 | for _, v := range b.Iterator() { 53 | ss = append(ss, fmt.Sprint(v)) 54 | } 55 | 56 | return "[" + strings.Join(ss, ", ") + "]" 57 | } 58 | -------------------------------------------------------------------------------- /strings/search/boyer_moore.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | // The bad-character rule part of the Boyer-Moore algorithm. 4 | // It does not implement the strong good suffix rule. 5 | type BoyerMoore struct { 6 | radix int 7 | right []int // the bad-character skip array 8 | pattern string 9 | } 10 | 11 | func NewBoyerMoore(pattern string) *BoyerMoore { 12 | radix := 256 13 | 14 | // position of rightmos occurrence of c in the pettern 15 | right := make([]int, radix) 16 | for i := 0; i < radix; i++ { 17 | right[i] = -1 18 | } 19 | for j := 0; j < len(pattern); j++ { 20 | right[pattern[j]] = j 21 | } 22 | 23 | return &BoyerMoore{radix, right, pattern} 24 | } 25 | 26 | // Returns the index of the first occurrence of the pattern sting 27 | // in the text string. 28 | // If no such match, renturn -1 29 | func (s *BoyerMoore) Search(txt string) int { 30 | m, n := len(s.pattern), len(txt) 31 | var skip int 32 | for i := 0; i <= n-m; i += skip { 33 | skip = 0 34 | for j := m - 1; j >= 0; j-- { 35 | if s.pattern[j] != txt[i+j] { 36 | k := int(txt[i+j]) 37 | skip = max(1, j-s.right[k]) 38 | break 39 | } 40 | } 41 | if skip == 0 { 42 | return i // found 43 | } 44 | } 45 | return -1 // not found 46 | } 47 | 48 | func max(i, j int) int { 49 | if j > i { 50 | return j 51 | } 52 | return i 53 | } 54 | -------------------------------------------------------------------------------- /searching/ordered_symbol_table.go: -------------------------------------------------------------------------------- 1 | package searching 2 | 3 | import "strings" 4 | 5 | // Ordered symbol tables. 6 | // In typical applications, keys are Comparable objects, so the option exists of 7 | // using a.CompareTo(b) to compare two keys a and b. Several symbol-table 8 | // implementations take advantage of order among the keys that is implied by 9 | // Comparable to provide efficient implementations of Put() and Get() operations. 10 | // More important, in such implementations, we can think of the symbol table as 11 | // keeping the keys in order and consider a significantly expanded API that 12 | // defines numerous and useful operations involving relative key order. 13 | 14 | type OrderedSymbolTable interface { 15 | Put(key OSTKey, value STValue) 16 | Get(key OSTKey) STValue 17 | Delete(key OSTKey) 18 | Contains(key OSTKey) bool 19 | Keys() []OSTKey 20 | } 21 | 22 | // OSTKey The key in ordered symbol tables 23 | type OSTKey interface { 24 | CompareTo(another OSTKey) int 25 | Equals(another OSTKey) bool 26 | } 27 | 28 | type StringKey string 29 | 30 | func (k StringKey) CompareTo(x OSTKey) int { 31 | s1 := string(k) 32 | s2 := string(x.(StringKey)) 33 | return strings.Compare(s1, s2) 34 | } 35 | 36 | func (k StringKey) Equals(x OSTKey) bool { 37 | s1 := string(k) 38 | s2 := string(x.(StringKey)) 39 | return s1 == s2 40 | } 41 | -------------------------------------------------------------------------------- /graphs/digraph/directed_dfs.go: -------------------------------------------------------------------------------- 1 | package digraph 2 | 3 | type DirectedDFS struct { 4 | marked []bool // marked[v]: true if v is reachable from source (s) 5 | count int // number of vertices reachable from source (s) 6 | } 7 | 8 | // Computes the vertices in graph (g) that are reachable from 9 | // the source vertex (s) 10 | func NewDirectedDFS(g Digraph, s int) DirectedDFS { 11 | g.validateVertex(s) 12 | marked := make([]bool, g.V()) 13 | 14 | search := DirectedDFS{marked, 0} 15 | search.dfs(g, s) 16 | 17 | return search 18 | } 19 | 20 | func NewDirectedDFSN(g Digraph, sources []int) DirectedDFS { 21 | marked := make([]bool, g.V()) 22 | 23 | search := DirectedDFS{marked, 0} 24 | for _, s := range sources { 25 | if !search.marked[s] { 26 | search.dfs(g, s) 27 | } 28 | } 29 | 30 | return search 31 | } 32 | 33 | // depth first search from s 34 | func (d DirectedDFS) dfs(g Digraph, s int) { 35 | d.count++ 36 | d.marked[s] = true 37 | 38 | for _, it := range g.Adj(s) { 39 | w := it.(int) 40 | if !d.marked[w] { 41 | d.dfs(g, w) 42 | } 43 | } 44 | } 45 | 46 | // Is there a path between the source vertex (s) and vertex (v) 47 | func (d DirectedDFS) Marked(v int) bool { 48 | return d.marked[v] 49 | } 50 | 51 | // Returns the number of vertices connected to the source vertex (s) 52 | func (d DirectedDFS) Count() int { 53 | return d.count 54 | } -------------------------------------------------------------------------------- /graphs/graph/depth_first_search.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | // Depth-first search is a classic recursive method for systematically examining 4 | // each of the vertices and edges in a graph. 5 | // To visit a vertex: 6 | // - Mark it as having been visited 7 | // - Visit (recursively) all the vertices that are adjacent to it and that have 8 | // not yet been marked 9 | 10 | type DepthFirstSearch struct { 11 | marked []bool // marked[v]: is there an s-v path? 12 | count int // number of vertices connected to s 13 | } 14 | 15 | // Computes the vertices in graph (g) that are connected to 16 | // the source vertex (s) 17 | func NewDepthFirstSearch(g Graph, s int) DepthFirstSearch { 18 | g.validateVertex(s) 19 | marked := make([]bool, g.V()) 20 | 21 | search := DepthFirstSearch{marked, 0} 22 | search.dfs(g, s) 23 | 24 | return search 25 | } 26 | 27 | // depth first search from s 28 | func (d DepthFirstSearch) dfs(g Graph, s int) { 29 | d.count++ 30 | d.marked[s] = true 31 | 32 | for _, ww := range g.Adj(s) { 33 | w := ww.(int) 34 | if !d.marked[w] { 35 | d.dfs(g, w) 36 | } 37 | } 38 | } 39 | 40 | // Is there a path between the source vertex (s) and vertex (v) 41 | func (d DepthFirstSearch) Marked(v int) bool { 42 | return d.marked[v] 43 | } 44 | 45 | // Returns the number of vertices connected to the source vertex (s) 46 | func (d DepthFirstSearch) Count() int { 47 | return d.count 48 | } 49 | -------------------------------------------------------------------------------- /strings/sort/example_test.go: -------------------------------------------------------------------------------- 1 | package sort_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/youngzhu/algs4-go/strings/sort" 7 | "github.com/youngzhu/algs4-go/testutil" 8 | ) 9 | 10 | func ExampleLSDSort() { 11 | in := testutil.NewInReadWords("testdata/words3.txt") 12 | a := in.ReadAllStrings() 13 | sort.LSDSort(a) 14 | 15 | fmt.Println(a) 16 | } 17 | 18 | func ExampleLSDSortInts() { 19 | ints := []int{1, 22, 55, 3, 2, 44, 0} 20 | sort.LSDSortInts(ints[:]) 21 | 22 | fmt.Println(ints) 23 | 24 | // -- 25 | // Output: 26 | // 27 | } 28 | 29 | func ExampleMSDSort() { 30 | in := testutil.NewInReadWords("testdata/shells.txt") 31 | a := in.ReadAllStrings() 32 | sort.MSDSort(a) 33 | 34 | for _, s := range a { 35 | fmt.Println(s) 36 | } 37 | 38 | // Output: 39 | // are 40 | // by 41 | // sea 42 | // seashells 43 | // seashells 44 | // sells 45 | // sells 46 | // she 47 | // she 48 | // shells 49 | // shore 50 | // surely 51 | // the 52 | // the 53 | } 54 | 55 | func ExampleQuicksort() { 56 | in := testutil.NewInReadWords("testdata/shells.txt") 57 | a := in.ReadAllStrings() 58 | sort.Quicksort(a) 59 | 60 | for _, s := range a { 61 | fmt.Println(s) 62 | } 63 | 64 | // Output: 65 | // are 66 | // by 67 | // sea 68 | // seashells 69 | // seashells 70 | // sells 71 | // sells 72 | // she 73 | // she 74 | // shells 75 | // shore 76 | // surely 77 | // the 78 | // the 79 | } 80 | -------------------------------------------------------------------------------- /sorting/pq/binary_heap_based1.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | // We represent complete binary trees sequentially within an array by putting 4 | // the nodes with level order, with the root at position 1, its children at 5 | // positions 2 and 3, their children in positions 4, 5, 6 and 7, and so on. 6 | 7 | // In a heap, the parent of the node in position k is in position k/2; and, conversely, 8 | // the two children of the node in position k are in positions 2k and 2k+1. We 9 | // can travel up and down by doing simple arithmetic on array indices: to move 10 | // up the tree from a[k] we set k to k/2; to move down the tree we set k to 2*k or 2*k+1. 11 | 12 | // binary heap using 1-based indexing 13 | type BinaryHeapBased1 struct{} 14 | 15 | func NewBinaryHeapBased1() BinaryHeapBased1 { 16 | return BinaryHeapBased1{} 17 | } 18 | 19 | // 1-based 20 | func (bh BinaryHeapBased1) GetLeftChildIndex(p, n int) int { 21 | leftChild := 2 * p 22 | if leftChild > n { 23 | return -1 // no valid left child 24 | } 25 | 26 | return leftChild 27 | } 28 | 29 | func (bh BinaryHeapBased1) GetRightChildIndex(p, n int) int { 30 | rightChild := 2*p + 1 31 | if rightChild > n { 32 | return -1 // no valid right child 33 | } 34 | 35 | return rightChild 36 | } 37 | 38 | func (bh BinaryHeapBased1) GetParentIndex(c, n int) int { 39 | if c <= 1 || c > n { 40 | return -1 41 | } 42 | 43 | return c / 2 44 | } 45 | 46 | func (bh BinaryHeapBased1) GetRootIndex() int { 47 | return 1 48 | } 49 | 50 | func (bh BinaryHeapBased1) GetLastLeafIndex(n int) int { 51 | return n 52 | } 53 | -------------------------------------------------------------------------------- /sorting/shell.go: -------------------------------------------------------------------------------- 1 | package sorting 2 | 3 | // ShellSort is simple extension of insertion sort that gains speed by allowing exchanges 4 | // of entries that are far apart, to produce partially sorted arrays that can be efficiently 5 | // sorted, eventually by insertion sort. 6 | // The idea is to rearrange the array to give it the property that taking every hth entry 7 | // (starting anywhere) yields a sorted sequence. Such an array is said to be h-sorted. 8 | // By h-sorting for some large values of h, we can move entries in the array long distances 9 | // and thus make it easier to h-sort for smaller values of h. Using such a procedure for any 10 | // increment sequence of values of h that ends in 1 will produce a sorted array: that is shell-sort. 11 | func ShellSort(x Sortable) { 12 | n := x.Len() 13 | 14 | // 3h+1 increment sequence: 1, 4, 13, 40, 121... 15 | h := 1 16 | for { 17 | if h >= n/3 { 18 | break 19 | } 20 | h = 3*h + 1 21 | } 22 | 23 | for { 24 | if h < 1 { 25 | break 26 | } 27 | // h-sort the array 28 | for i := h; i < n; i++ { 29 | for j := i; j >= h && x.Less(j, j-h); j -= h { 30 | x.Swap(j, j-h) 31 | } 32 | } 33 | h /= 3 34 | } 35 | 36 | } 37 | 38 | type Shell struct{} 39 | 40 | func NewShell() Sorter { 41 | return Shell{} 42 | } 43 | 44 | // Implements Sorter 45 | 46 | func (s Shell) SortInts(x []int) { 47 | ShellSort(IntSortSlice(x)) 48 | } 49 | func (s Shell) SortFloat64s(x []float64) { 50 | ShellSort(Float64SortSlice(x)) 51 | } 52 | func (s Shell) SortStrings(x []string) { 53 | ShellSort(StringSortSlice(x)) 54 | } 55 | -------------------------------------------------------------------------------- /fund/uf/quick_find.go: -------------------------------------------------------------------------------- 1 | package uf 2 | 3 | // QuickFind Quick-find algorithm. 4 | // It maintains the invariant that p and q are connected if and only if 5 | // id[p] = id[q]. In other words, all sites in a component must have the 6 | // same value in id[] 7 | type QuickFind struct { 8 | id []int // id[i]: component identifier of i 9 | count int // number of components 10 | } 11 | 12 | // NewQuickFind returns an empty union-find data structure with n elements (0...n-1) 13 | // Initially, each element is in its own set. 14 | func NewQuickFind(n int) *QuickFind { 15 | id := make([]int, n) 16 | for i := 0; i < n; i++ { 17 | id[i] = i 18 | } 19 | 20 | return &QuickFind{id, n} 21 | } 22 | 23 | func (qf *QuickFind) Find(p int) int { 24 | qf.validate(p) 25 | return qf.id[p] 26 | } 27 | 28 | func (qf *QuickFind) Union(p, q int) { 29 | qf.validate(p) 30 | qf.validate(q) 31 | 32 | // needed for correctness to reduce the number of array accesses 33 | pID := qf.id[p] 34 | qID := qf.id[q] 35 | 36 | // p and q are already in the same component 37 | if pID == qID { 38 | return 39 | } 40 | 41 | n := len(qf.id) 42 | for i := 0; i < n; i++ { 43 | if qf.id[i] == pID { 44 | qf.id[i] = qID 45 | } 46 | } 47 | 48 | qf.count-- 49 | } 50 | 51 | func (qf *QuickFind) Count() int { 52 | return qf.count 53 | } 54 | 55 | func (qf *QuickFind) Connected(p, q int) bool { 56 | qf.validate(p) 57 | qf.validate(q) 58 | return qf.id[p] == qf.id[q] 59 | } 60 | 61 | func (qf *QuickFind) validate(p int) { 62 | n := len(qf.id) 63 | if p < 0 || p >= n { 64 | panic("invalid index") 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /fund/evaluate.go: -------------------------------------------------------------------------------- 1 | package fund 2 | 3 | import ( 4 | "strings" 5 | "strconv" 6 | ) 7 | 8 | // Arithmetic expression evaluation. 9 | // Evaluate() is a stack client that evaluates fully parenthesized arithmetic 10 | // expressions. It uses Dijkstra's 2-stack algorithm: 11 | // - Push operands onto the operand stack 12 | // - Push operators onto the operator stack 13 | // - Ignore left parentheses 14 | // - On encountering a right parenthesis, pop an operator, pop the requisite 15 | // number of operands, and push onto the operand stack the result of applying 16 | // that operator to those operands. 17 | 18 | func Evaluate(exp string) float64 { 19 | operators := NewStack() 20 | operands := NewStack() 21 | 22 | ss := strings.Fields(exp) 23 | 24 | for _, s := range ss { 25 | // fmt.Println(s) 26 | 27 | if s == "(" { 28 | // ignore 29 | } else if isOperator(s) { 30 | operators.Push(s) 31 | } else if s == ")" { 32 | op := operators.Pop() 33 | v := operands.Pop().(float64) 34 | 35 | if op == "+" { 36 | v = operands.Pop().(float64) + v 37 | } else if op == "-" { 38 | v = operands.Pop().(float64) - v 39 | } else if op == "*" { 40 | v = operands.Pop().(float64) * v 41 | } else if op == "/" { 42 | v = operands.Pop().(float64) / v 43 | } 44 | 45 | operands.Push(v) 46 | 47 | } else { 48 | operand, err := strconv.ParseFloat(s, 64) 49 | if err != nil { 50 | panic("invalid operand: " + s) 51 | } 52 | operands.Push(operand) 53 | } 54 | } 55 | 56 | return operands.Pop().(float64) 57 | } 58 | 59 | func isOperator(s string) bool { 60 | switch s { 61 | case "+", "-", "*", "/": 62 | return true 63 | } 64 | return false 65 | } 66 | -------------------------------------------------------------------------------- /graphs/digraph/depth_first_directed_paths.go: -------------------------------------------------------------------------------- 1 | package digraph 2 | 3 | import "github.com/youngzhu/algs4-go/fund" 4 | 5 | type DepthFirstDirectedPaths struct { 6 | graph Digraph 7 | source int // source vertex 8 | marked []bool // marked[v]: is there an s-v path? 9 | edgeTo []int // edgeTo[v]: last edge on s-v path 10 | } 11 | 12 | // Computes a path between the source vertex (s) and every other vertex in graph g 13 | func NewDepthFirstDirectedPaths(g Digraph, s int) DepthFirstDirectedPaths { 14 | g.validateVertex(s) 15 | 16 | marked := make([]bool, g.V()) 17 | edgeTo := make([]int, g.V()) 18 | 19 | path := DepthFirstDirectedPaths{g, s, marked, edgeTo} 20 | path.dfs(g, s) 21 | 22 | return path 23 | } 24 | 25 | // depth first search from v 26 | func (p DepthFirstDirectedPaths) dfs(g Digraph, v int) { 27 | p.marked[v] = true 28 | 29 | for _, it := range g.Adj(v) { 30 | w := it.(int) 31 | if !p.marked[w] { 32 | p.edgeTo[w] = v 33 | p.dfs(g, w) 34 | } 35 | } 36 | } 37 | 38 | // Is there a path between the source vertex (s) and vertex (v) 39 | func (p DepthFirstDirectedPaths) HasPathTo(v int) bool { 40 | p.graph.validateVertex(v) 41 | return p.marked[v] 42 | } 43 | 44 | // Returns a path between the source vertex (s) and vertex v 45 | // or nil if no such path 46 | func (p DepthFirstDirectedPaths) PathTo(v int) []int { 47 | if !p.HasPathTo(v) { 48 | return nil 49 | } 50 | 51 | stack := fund.NewStack() 52 | 53 | for x := v; x != p.source; x = p.edgeTo[x] { 54 | stack.Push(fund.Item(x)) 55 | } 56 | stack.Push(fund.Item(p.source)) 57 | 58 | path := make([]int, stack.Size()) 59 | i := 0 60 | for !stack.IsEmpty() { 61 | path[i] = stack.Pop().(int) 62 | i++ 63 | } 64 | 65 | return path 66 | } -------------------------------------------------------------------------------- /fund/uf/weighted_quick_union.go: -------------------------------------------------------------------------------- 1 | package uf 2 | 3 | // WeightedQuickUnion Weighted quick-union algorithm (without path compression). 4 | // Rather than arbitrarily connecting the second tree to the first for Union() 5 | // in the quick-union algorithm, we keep track of the size of each tree and 6 | // always connect the smaller tree to the larger. 7 | type WeightedQuickUnion struct { 8 | parent []int // parent[i]: parent of i 9 | count int // number of components 10 | size []int // size[i]: number of elements in subtree rooted at i 11 | } 12 | 13 | func NewWeightedQuickUnion(n int) *WeightedQuickUnion { 14 | parent := make([]int, n) 15 | size := make([]int, n) 16 | for i := 0; i < n; i++ { 17 | parent[i] = i 18 | size[i] = 1 19 | } 20 | 21 | return &WeightedQuickUnion{parent, n, size} 22 | } 23 | 24 | func (qu *WeightedQuickUnion) Union(p, q int) { 25 | rootP := qu.Find(p) 26 | rootQ := qu.Find(q) 27 | if rootP == rootQ { 28 | return 29 | } 30 | 31 | // make smaller root point to larger one 32 | if qu.size[rootP] < qu.size[rootQ] { 33 | qu.parent[rootP] = rootQ 34 | qu.size[rootQ] += qu.size[rootP] 35 | } else { 36 | qu.parent[rootQ] = rootP 37 | qu.size[rootP] += qu.size[rootQ] 38 | } 39 | 40 | qu.count-- 41 | } 42 | 43 | func (qu *WeightedQuickUnion) Find(p int) int { 44 | qu.validate(p) 45 | for p != qu.parent[p] { 46 | p = qu.parent[p] 47 | } 48 | return p 49 | } 50 | 51 | func (qu *WeightedQuickUnion) Count() int { 52 | return qu.count 53 | } 54 | 55 | func (qu *WeightedQuickUnion) Connected(p, q int) bool { 56 | return qu.Find(p) == qu.Find(q) 57 | } 58 | 59 | func (qu *WeightedQuickUnion) validate(p int) { 60 | n := len(qu.parent) 61 | if p < 0 || p >= n { 62 | panic("invalid index") 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /graphs/digraph/testdata/mediumDG.txt: -------------------------------------------------------------------------------- 1 | 50 2 | 147 3 | 0 7 4 | 0 34 5 | 1 14 6 | 1 45 7 | 1 21 8 | 1 22 9 | 1 22 10 | 1 49 11 | 2 19 12 | 2 25 13 | 2 33 14 | 3 4 15 | 3 17 16 | 3 27 17 | 3 36 18 | 3 42 19 | 4 17 20 | 4 17 21 | 4 27 22 | 5 43 23 | 6 13 24 | 6 13 25 | 6 28 26 | 6 28 27 | 7 41 28 | 7 44 29 | 8 19 30 | 8 48 31 | 9 9 32 | 9 11 33 | 9 30 34 | 9 46 35 | 10 0 36 | 10 7 37 | 10 28 38 | 10 28 39 | 10 28 40 | 10 29 41 | 10 29 42 | 10 34 43 | 10 41 44 | 11 21 45 | 11 30 46 | 12 9 47 | 12 11 48 | 12 21 49 | 12 21 50 | 12 26 51 | 13 22 52 | 13 23 53 | 13 47 54 | 14 8 55 | 14 21 56 | 14 48 57 | 15 8 58 | 15 34 59 | 15 49 60 | 16 9 61 | 17 20 62 | 17 24 63 | 17 38 64 | 18 6 65 | 18 28 66 | 18 32 67 | 18 42 68 | 19 15 69 | 19 40 70 | 20 3 71 | 20 35 72 | 20 38 73 | 20 46 74 | 22 6 75 | 23 11 76 | 23 21 77 | 23 22 78 | 24 4 79 | 24 5 80 | 24 38 81 | 24 43 82 | 25 2 83 | 25 34 84 | 26 9 85 | 26 12 86 | 26 16 87 | 27 5 88 | 27 24 89 | 27 32 90 | 27 31 91 | 27 42 92 | 28 22 93 | 28 29 94 | 28 39 95 | 28 44 96 | 29 22 97 | 29 49 98 | 30 23 99 | 30 37 100 | 31 18 101 | 31 32 102 | 32 5 103 | 32 6 104 | 32 13 105 | 32 37 106 | 32 47 107 | 33 2 108 | 33 8 109 | 33 19 110 | 34 2 111 | 34 19 112 | 34 40 113 | 35 9 114 | 35 37 115 | 35 46 116 | 36 20 117 | 36 42 118 | 37 5 119 | 37 9 120 | 37 35 121 | 37 47 122 | 37 47 123 | 38 35 124 | 38 37 125 | 38 38 126 | 39 18 127 | 39 42 128 | 40 15 129 | 41 28 130 | 41 44 131 | 42 31 132 | 43 37 133 | 43 38 134 | 44 39 135 | 45 8 136 | 45 14 137 | 45 14 138 | 45 15 139 | 45 49 140 | 46 16 141 | 47 23 142 | 47 30 143 | 48 12 144 | 48 21 145 | 48 33 146 | 48 33 147 | 49 34 148 | 49 22 149 | 49 49 150 | -------------------------------------------------------------------------------- /strings/search/bench_test.go: -------------------------------------------------------------------------------- 1 | package search_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/youngzhu/algs4-go/strings/search" 7 | ) 8 | 9 | // go test -v -run="none" -bench="." -benchtime="3s" 10 | 11 | var benchCases = []struct { 12 | pattern, text string 13 | }{ 14 | {"abracadabra", "abacadabrabracabracadabrabrabracad"}, 15 | {"rab", "abacadabrabracabracadabrabrabracad"}, 16 | {"rabrabracad", "abacadabrabracabracadabrabrabracad"}, 17 | {"bcara", "abacadabrabracabracadabrabrabracad"}, 18 | {"abacad", "abacadabrabracabracadabrabrabracad"}, 19 | } 20 | 21 | func BenchmarkBruteForceSearch1(b *testing.B) { 22 | b.ReportAllocs() 23 | b.ResetTimer() 24 | 25 | for i := 0; i < b.N; i++ { 26 | for _, tc := range benchCases { 27 | BruteForceSearch1(tc.pattern, tc.text) 28 | } 29 | } 30 | } 31 | 32 | func BenchmarkBruteForceSearch2(b *testing.B) { 33 | b.ReportAllocs() 34 | b.ResetTimer() 35 | 36 | for i := 0; i < b.N; i++ { 37 | for _, tc := range benchCases { 38 | BruteForceSearch2(tc.pattern, tc.text) 39 | } 40 | } 41 | } 42 | 43 | func BenchmarkRabinKarpSearch(b *testing.B) { 44 | b.ReportAllocs() 45 | b.ResetTimer() 46 | 47 | for i := 0; i < b.N; i++ { 48 | for _, tc := range benchCases { 49 | RabinKarpSearch(tc.pattern, tc.text) 50 | } 51 | } 52 | } 53 | 54 | func BenchmarkKMPSearch(b *testing.B) { 55 | b.ReportAllocs() 56 | b.ResetTimer() 57 | 58 | for i := 0; i < b.N; i++ { 59 | for _, tc := range benchCases { 60 | KMPSearch(tc.pattern, tc.text) 61 | } 62 | } 63 | } 64 | 65 | func BenchmarkBoyerMooreSearch(b *testing.B) { 66 | b.ReportAllocs() 67 | b.ResetTimer() 68 | 69 | for i := 0; i < b.N; i++ { 70 | for _, tc := range benchCases { 71 | BoyerMooreSearch(tc.pattern, tc.text) 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /graphs/mst/kruskal_mst.go: -------------------------------------------------------------------------------- 1 | package mst 2 | 3 | import ( 4 | "github.com/youngzhu/algs4-go/fund" 5 | "github.com/youngzhu/algs4-go/fund/uf" 6 | "github.com/youngzhu/algs4-go/sorting/pq" 7 | ) 8 | 9 | // Kruskal's algorithm processes the edges in order of their weight values 10 | // (smallest to largest), taking for the MST (coloring black) each edge that 11 | // does not form a cycle with edges previously added, stopping after adding 12 | // V-1 edges. The black edges form a forest of trees that evolves gradually 13 | // into a single tree, the MST. 14 | // To implement Kruskal's algorithm, we use a priority queue to consider the 15 | // edges in order by weight, a union-find data structure to indentify those 16 | // that cause cycles, and a queue to collect the MST edges. 17 | type KruskalMST struct { 18 | weight float64 // weight of MST 19 | mst *fund.Queue // edges in MST 20 | } 21 | 22 | func NewKruskalMST(g EdgeWeightedGraph) *KruskalMST { 23 | minPQ := pq.NewMinPQ() 24 | 25 | for _, e := range g.Edges() { 26 | minPQ.Insert(e.(*Edge)) 27 | } 28 | 29 | mst := fund.NewQueue() 30 | weight := 0.0 31 | 32 | // run greedy algorithm 33 | unionFind := uf.NewUF(g.V()) 34 | for !minPQ.IsEmpty() && mst.Size() < g.V()-1 { 35 | e := minPQ.Delete().(*Edge) 36 | v := e.Either() 37 | w := e.Other(v) 38 | 39 | // v-w does not create a cycle 40 | if unionFind.Find(v) != unionFind.Find(w) { 41 | unionFind.Union(v, w) // merge v and w components 42 | mst.Enqueue(e) // add edge e to mst 43 | weight += e.Weight() 44 | } 45 | } 46 | 47 | return &KruskalMST{weight, mst} 48 | } 49 | 50 | // Returns the edges in a MST 51 | func (k *KruskalMST) Edges() fund.Iterator { 52 | return k.mst.Iterator() 53 | } 54 | 55 | // Returns the sum of edge weights in a MST 56 | func (k *KruskalMST) Weight() float64 { 57 | return k.weight 58 | } -------------------------------------------------------------------------------- /graphs/graph/connected_components.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | // Another client of DFS, find the connected components of a graph. 4 | type ConnectedComponents struct { 5 | graph Graph 6 | marked []bool // makred[v]: has vertex v been marked? 7 | id []int // id[v]: id of connected component containing v 8 | size []int // size[id]: number of vertices in given component 9 | count int // number of connected components 10 | } 11 | 12 | func NewConnectedComponents(g Graph) ConnectedComponents { 13 | marked := make([]bool, g.V()) 14 | id := make([]int, g.V()) 15 | size := make([]int, g.V()) 16 | 17 | cc := ConnectedComponents{g, marked, id, size, 0} 18 | 19 | for v := 0; v < g.V(); v++ { 20 | if !cc.marked[v] { 21 | cc.dfs(v) 22 | cc.count++ 23 | } 24 | } 25 | 26 | return cc 27 | } 28 | 29 | func (cc ConnectedComponents) dfs(v int) { 30 | cc.marked[v] = true 31 | cc.id[v] = cc.count 32 | cc.size[cc.count]++ 33 | for _, ww := range cc.graph.Adj(v) { 34 | w := ww.(int) 35 | if !cc.marked[w] { 36 | cc.dfs(w) 37 | } 38 | } 39 | } 40 | 41 | // Returns the component id of the connected component containing vertex v 42 | func (cc ConnectedComponents) Id(v int) int { 43 | cc.graph.validateVertex(v) 44 | return cc.id[v] 45 | } 46 | 47 | // Returns the number of vertices in the connected compoent containing vertex v 48 | func (cc ConnectedComponents) Size(v int) int { 49 | cc.graph.validateVertex(v) 50 | return cc.size[v] 51 | } 52 | 53 | // Returns the number of connected components in the graph 54 | func (cc ConnectedComponents) Count() int { 55 | return cc.count 56 | } 57 | 58 | // Returns true if vertices v and w are in the same connected component 59 | func (cc ConnectedComponents) Connected(v, w int) bool { 60 | cc.graph.validateVertex(v) 61 | cc.graph.validateVertex(w) 62 | return cc.id[v] == cc.id[w] 63 | } 64 | -------------------------------------------------------------------------------- /searching/hash_symbol_table.go: -------------------------------------------------------------------------------- 1 | package searching 2 | 3 | // If keys are small integers, we can use an array to implement a symbol table, 4 | // by interpreting the key as an array index so that we can store the value 5 | // associated with key i in array position i. 6 | 7 | // Search algorithms that use hashing consist of two separate parts. The head 8 | // step is to compute a hash function that transforms the search key into an 9 | // array index. Ideally, different keys would map to different indices. This 10 | // ideal is generally beyond our reach, so we have to face the possibility that 11 | // two or more different keys may hash to the same array index. Thus, the second 12 | // part of a hasing search is a collision-resolution process that deals with 13 | // this situation. 14 | 15 | // Hash functions. 16 | // If we have an array that can hold M key-value pairs, then we need a function 17 | // that can transform any given key into an index into that array: an integer in 18 | // the range [0, M-1]. We seek a hash function that is both easy to compute and 19 | // uniformly distributes the keys. 20 | 21 | // We have 3 primary requirements in implementing a good hash function for a given key 22 | // 1. It should be deterministic--equal keys must produce the same hash value 23 | // 2. It should be efficient to compute 24 | // 3. It should uniformly distribute the keys 25 | 26 | // must be a power of 2 27 | const initHashCapacity = 4 28 | 29 | type HashSymbolTable interface { 30 | Put(key HashSTKey, value STValue) 31 | Get(key HashSTKey) STValue 32 | Delete(key HashSTKey) 33 | Contains(key HashSTKey) bool 34 | Keys() []HashSTKey 35 | } 36 | 37 | type HashSTKey interface { 38 | hashCode() int 39 | } 40 | 41 | type StringHashKey string 42 | 43 | func (s StringHashKey) hashCode() int { 44 | hash := 0 45 | 46 | for _, v := range s { 47 | hash = 31*hash + int(v) 48 | } 49 | 50 | return hash 51 | } 52 | -------------------------------------------------------------------------------- /searching/example_test.go: -------------------------------------------------------------------------------- 1 | package searching_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/youngzhu/algs4-go/searching" 7 | ) 8 | 9 | var tinyST = []string{"S", "E", "A", "R", "C", "H", "E", "X", "A", "M", "P", "L", "E"} 10 | 11 | func ExampleSequentialSearchST() { 12 | st := searching.NewSequentialSearchST() 13 | for i, v := range tinyST { 14 | st.Put(searching.StringKey(v), i) 15 | } 16 | 17 | for _, key := range st.Keys() { 18 | fmt.Println(key, st.Get(key)) 19 | } 20 | 21 | // Output: 22 | // L 11 23 | // P 10 24 | // M 9 25 | // X 7 26 | // H 5 27 | // C 4 28 | // R 3 29 | // A 8 30 | // E 12 31 | // S 0 32 | } 33 | 34 | func ExampleBinarySearchST() { 35 | st := searching.NewBinarySearchST() 36 | for i, v := range tinyST { 37 | st.Put(searching.StringKey(v), i) 38 | } 39 | 40 | for _, key := range st.Keys() { 41 | fmt.Println(key, st.Get(key)) 42 | } 43 | 44 | // Output: 45 | // A 8 46 | // C 4 47 | // E 12 48 | // H 5 49 | // L 11 50 | // M 9 51 | // P 10 52 | // R 3 53 | // S 0 54 | // X 7 55 | } 56 | 57 | func ExampleBST() { 58 | st := searching.NewBST() 59 | for i, v := range tinyST { 60 | st.Put(searching.StringKey(v), i) 61 | } 62 | 63 | for _, key := range st.Keys() { 64 | fmt.Println(key, st.Get(key)) 65 | } 66 | 67 | // Output: 68 | // A 8 69 | // C 4 70 | // E 12 71 | // H 5 72 | // L 11 73 | // M 9 74 | // P 10 75 | // R 3 76 | // S 0 77 | // X 7 78 | } 79 | 80 | func ExampleRedBlackBST() { 81 | st := searching.NewRedBlackBST() 82 | for i, v := range tinyST { 83 | st.Put(searching.StringKey(v), i) 84 | } 85 | 86 | for _, key := range st.Keys() { 87 | fmt.Println(key, st.Get(key)) 88 | } 89 | 90 | // Output: 91 | // A 8 92 | // C 4 93 | // E 12 94 | // H 5 95 | // L 11 96 | // M 9 97 | // P 10 98 | // R 3 99 | // S 0 100 | // X 7 101 | } 102 | -------------------------------------------------------------------------------- /fund/uf/quick_union.go: -------------------------------------------------------------------------------- 1 | package uf 2 | 3 | // QuickUnion is a Quick-union algorithm. 4 | // It's based on the same data structure—the site-indexed id[] array—but 5 | // it uses a different interpretation of the values that leads to more 6 | // complicated structures. Specifically, the id[] entry for each site will 7 | // be the name of another site in the same component (possibly itself). 8 | // To implement Find() we start at the given site, follow its link to 9 | // another site, follow that sites link to yet another site, and so forth, 10 | // following links until reaching a root, a site that has a link to itself. 11 | // Two sites are in the same component if and only if this process leads 12 | // them to the same root. To validate this process, we need Union() to 13 | // maintain this invariant, which is easily arranged: we follow links to 14 | // find the roots associated with each of the given sites, then rename one 15 | // of the components by linking one of these roots to the other. 16 | type QuickUnion struct { 17 | parent []int // parent[i]: parent of i 18 | count int // number of components 19 | } 20 | 21 | func NewQuickUnion(n int) *QuickUnion { 22 | parent := make([]int, n) 23 | for i := 0; i < n; i++ { 24 | parent[i] = i 25 | } 26 | 27 | return &QuickUnion{parent, n} 28 | } 29 | 30 | func (qu *QuickUnion) Union(p, q int) { 31 | rootP := qu.Find(p) 32 | rootQ := qu.Find(q) 33 | if rootP == rootQ { 34 | return 35 | } 36 | qu.parent[rootP] = rootQ 37 | qu.count-- 38 | } 39 | 40 | func (qu *QuickUnion) Find(p int) int { 41 | qu.validate(p) 42 | for p != qu.parent[p] { 43 | p = qu.parent[p] 44 | } 45 | return p 46 | } 47 | 48 | func (qu *QuickUnion) Count() int { 49 | return qu.count 50 | } 51 | 52 | func (qu *QuickUnion) Connected(p, q int) bool { 53 | return qu.Find(p) == qu.Find(q) 54 | } 55 | 56 | func (qu *QuickUnion) validate(p int) { 57 | n := len(qu.parent) 58 | if p < 0 || p >= n { 59 | panic("invalid index") 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /graphs/graph/depth_first_paths.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import "github.com/youngzhu/algs4-go/fund" 4 | 5 | // We remember the edge v-w that takes us to each vertex w for the first time 6 | // by setting edge[w] to v. In other words, v-w is the last edge on the known 7 | // path from s to w. The result of the search is a tree rooted at the source; 8 | // edgeTo[] is a parent-link representation of that tree. 9 | 10 | type DepthFirstPaths struct { 11 | graph Graph 12 | source int // source vertex 13 | marked []bool // marked[v]: is there an s-v path? 14 | edgeTo []int // edgeTo[v]: last edge on s-v path 15 | } 16 | 17 | // Computes a path between the source vertex (s) and every other vertex in graph g 18 | func NewDepthFirstPaths(g Graph, s int) DepthFirstPaths { 19 | g.validateVertex(s) 20 | 21 | marked := make([]bool, g.V()) 22 | edgeTo := make([]int, g.V()) 23 | 24 | path := DepthFirstPaths{g, s, marked, edgeTo} 25 | path.dfs(g, s) 26 | 27 | return path 28 | } 29 | 30 | // depth first search from v 31 | func (p DepthFirstPaths) dfs(g Graph, v int) { 32 | p.marked[v] = true 33 | 34 | for _, ww := range g.Adj(v) { 35 | w := ww.(int) 36 | if !p.marked[w] { 37 | p.edgeTo[w] = v 38 | p.dfs(g, w) 39 | } 40 | } 41 | } 42 | 43 | // Is there a path between the source vertex (s) and vertex (v) 44 | func (p DepthFirstPaths) HasPathTo(v int) bool { 45 | p.graph.validateVertex(v) 46 | return p.marked[v] 47 | } 48 | 49 | // Returns a path between the source vertex (s) and vertex v 50 | // or nil if no such path 51 | func (p DepthFirstPaths) PathTo(v int) []int { 52 | if !p.HasPathTo(v) { 53 | return nil 54 | } 55 | 56 | stack := fund.NewStack() 57 | 58 | for x := v; x != p.source; x = p.edgeTo[x] { 59 | stack.Push(fund.Item(x)) 60 | } 61 | stack.Push(fund.Item(p.source)) 62 | 63 | path := make([]int, stack.Size()) 64 | i := 0 65 | for !stack.IsEmpty() { 66 | path[i] = stack.Pop().(int) 67 | i++ 68 | } 69 | 70 | return path 71 | } 72 | -------------------------------------------------------------------------------- /strings/search/rabin_karp.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | import "crypto/rand" 4 | 5 | // Rabin-Karp randomized fingerprint algorithm. 6 | type RabinKarp struct { 7 | patternHash int // pattern hash value 8 | m int // pattern length 9 | q int // a large prime, small enough to avoid overflow 10 | r int // radix 11 | rm int // r^(m-1)%q 12 | } 13 | 14 | func NewRabinKarp(pattern string) *RabinKarp { 15 | r := 256 16 | m := len(pattern) 17 | q := longRandomPrime() 18 | 19 | // precompute r^(m-1)%q for use in removing leading digit 20 | rm := 1 21 | for i := 1; i <= m-1; i++ { 22 | rm = (r * rm) % q 23 | } 24 | 25 | rk := &RabinKarp{m: m, q: q, r: r, rm: rm} 26 | 27 | rk.patternHash = rk.hash(pattern) 28 | 29 | return rk 30 | } 31 | 32 | // compute hash for key[0..m-1] 33 | func (rk *RabinKarp) hash(key string) int { 34 | h := 0 35 | for j := 0; j < rk.m; j++ { 36 | h = (rk.r*h + int(key[j])) % rk.q 37 | } 38 | return h 39 | } 40 | 41 | // Returns the index of the first occurrence of the pattern sting 42 | // in the text string. 43 | // If no such match, renturn -1 44 | func (rk *RabinKarp) Search(txt string) int { 45 | n := len(txt) 46 | if n < rk.m { 47 | return -1 48 | } 49 | 50 | txtHash := rk.hash(txt) 51 | 52 | // check for match at offset 0 53 | if txtHash == rk.patternHash { 54 | return 0 55 | } 56 | 57 | // check for hash match 58 | // if hash match, check for exact match 59 | for i := rk.m; i < n; i++ { 60 | // remove leading digit, add trailing digit, check for match 61 | k := int(txt[i-rk.m]) 62 | txtHash = (txtHash + rk.q - rk.rm*k%rk.q) % rk.q 63 | txtHash = (txtHash*rk.r + int(txt[i])) % rk.q 64 | 65 | // match 66 | if txtHash == rk.patternHash { 67 | return i - rk.m + 1 68 | } 69 | } 70 | 71 | // no match 72 | return -1 73 | } 74 | 75 | // a random 31-bit prime 76 | func longRandomPrime() int { 77 | prime, _ := rand.Prime(rand.Reader, 31) 78 | return int(prime.Int64()) 79 | } 80 | -------------------------------------------------------------------------------- /graphs/digraph/directed_cycle.go: -------------------------------------------------------------------------------- 1 | package digraph 2 | 3 | // import "log" 4 | import "github.com/youngzhu/algs4-go/fund" 5 | 6 | // Does a given digraph have a directed cycle? 7 | // Solves this problem using depth-first search 8 | 9 | type DirectedCycle struct { 10 | marked []bool // marked[v]: has vertex v been marked? 11 | edgeTo []int // edgeTo[v]: previous vertex on path to v 12 | onStack []bool // onStack[v]: is vertex on the stack? 13 | cycle *fund.Stack // directed cycle (or nil if no such cycle) 14 | } 15 | 16 | func NewDirectedCycle(g IDigraph) *DirectedCycle { 17 | marked := make([]bool, g.V()) 18 | edgeTo := make([]int, g.V()) 19 | onStack := make([]bool, g.V()) 20 | dc := &DirectedCycle{marked, edgeTo, onStack, nil} 21 | 22 | // log.Println(dc.graph.String()) 23 | 24 | for v := 0; v < g.V(); v++ { 25 | if !dc.marked[v] && dc.cycle == nil { 26 | dc.dfs(g, v) 27 | } 28 | } 29 | 30 | return dc 31 | } 32 | 33 | // run DFS and find a directed cycle 34 | // must use pointer (*), otherwise dc.cycle wouldn't change 35 | func (dc *DirectedCycle) dfs(g IDigraph, v int) { 36 | dc.onStack[v] = true 37 | dc.marked[v] = true 38 | 39 | for _, it := range g.Adj(v) { 40 | w := it.(int) 41 | // short circuit if directed cycle found 42 | // log.Printf("cycle: %v", dc.cycle!= nil) 43 | if dc.cycle != nil { 44 | return 45 | } else if !dc.marked[w] { // found new vertex, so recur 46 | dc.edgeTo[w] = v 47 | dc.dfs(g, w) 48 | } else if dc.onStack[w] { // trace back directed cycle 49 | cycle := fund.NewStack() 50 | for x := v; x != w; x = dc.edgeTo[x] { 51 | cycle.Push(x) 52 | } 53 | cycle.Push(w) 54 | cycle.Push(v) 55 | // log.Println(w) 56 | dc.cycle = cycle 57 | } 58 | } 59 | 60 | dc.onStack[v] = false 61 | } 62 | 63 | // Does the digraph have a directed cycle? 64 | func (dc *DirectedCycle) HasCycle() bool { 65 | return dc.cycle != nil 66 | } 67 | 68 | func (dc *DirectedCycle) Cycle() fund.Iterator { 69 | if dc.HasCycle() { 70 | return dc.cycle.Iterator() 71 | } 72 | 73 | return nil 74 | } -------------------------------------------------------------------------------- /sorting/pq/priority_queue.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | // Many applications require that we process items having keys in order, but not 4 | // necessarily in full sorted order and not necessarily all at once. Often, we 5 | // collect a set of items, then process the one with the largest key, then perhaps 6 | // collect more items, then process the one with the current largest key, and so forth. 7 | // An appropriate data type in such an environment supports two operations: remove 8 | // and insert. Such a data type is called a priority queue. 9 | 10 | type PriorityQueue interface { 11 | Insert(item Item) 12 | Delete() Item 13 | IsEmpty() bool 14 | Size() int 15 | } 16 | 17 | // IndexPriorityQueue 18 | // In many applications, it makes sense to allow client refer to items that 19 | // are already on the priority queue. One easy way to do so is to associate 20 | // a unique integer index with each item. 21 | type IndexPriorityQueue interface { 22 | // Insert inserts item, associate it with k 23 | Insert(k int, item Item) 24 | 25 | // Update updates the item associated with k to item 26 | Update(k int, item Item) 27 | 28 | // Contains report is k associated with any item? 29 | Contains(k int) bool 30 | 31 | // Delete remove the minimal/maximal item and return its index 32 | Delete() int 33 | 34 | // IsEmpty report is the priority queue empty? 35 | IsEmpty() bool 36 | 37 | // Size return number of items in the priority queue 38 | Size() int 39 | 40 | // HighestPriorityItem get the minimal/maximal item 41 | HighestPriorityItem() Item 42 | } 43 | 44 | type Item interface { 45 | CompareTo(x Item) int 46 | } 47 | 48 | type StringItem string 49 | 50 | func (s StringItem) CompareTo(x Item) int { 51 | ss := x.(StringItem) 52 | if s < ss { 53 | return -1 54 | } else if s > ss { 55 | return 1 56 | } else { 57 | return 0 58 | } 59 | } 60 | 61 | type IntItem int 62 | 63 | func (i IntItem) CompareTo(x Item) int { 64 | ii := x.(IntItem) 65 | if i < ii { 66 | return -1 67 | } else if i > ii { 68 | return 1 69 | } else { 70 | return 0 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /fund/stack.go: -------------------------------------------------------------------------------- 1 | package fund 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | // Pushdown stack. 9 | // A pushdown stack is a collection that is based on the last-in-first-out (LIFO) 10 | // policy. When you click a hyperlink, your browser displays the new page (and 11 | // pushes onto a stack). You can keep clicking on hyperlinks to visit new pages, 12 | // but you can always revisit the previous page by clicking the back button 13 | // (popping it from the stack). 14 | 15 | // Stack implemented using a singly linked list 16 | type Stack struct { 17 | top *Node // top of stack 18 | size int // size of the stack 19 | } 20 | 21 | func NewStack() *Stack { 22 | return &Stack{} 23 | } 24 | 25 | // Push adds the item to this stack 26 | func (s *Stack) Push(item Item) { 27 | s.top = newNode(item, s.top) 28 | s.size++ 29 | } 30 | 31 | // Pop removes and returns the item most recently added to this stack 32 | func (s *Stack) Pop() Item { 33 | if s.IsEmpty() { 34 | panic("stack is empty") 35 | } 36 | 37 | item := s.top.item // save item to return 38 | s.top = s.top.next // delete first node 39 | s.size-- 40 | 41 | return item 42 | } 43 | 44 | // Peek returns (but does not remove) the item most recently added to this stack 45 | func (s *Stack) Peek() Item { 46 | if s.IsEmpty() { 47 | panic("stack is empty") 48 | } 49 | 50 | return s.top.item 51 | } 52 | 53 | // IsEmpty returns true if this stack is empty 54 | func (s *Stack) IsEmpty() bool { 55 | return s.top == nil 56 | } 57 | 58 | // Size returns the number of items in this stack 59 | func (s *Stack) Size() int { 60 | return s.size 61 | } 62 | 63 | func (s *Stack) Iterator() Iterator { 64 | items := make([]interface{}, s.size) 65 | 66 | i := 0 67 | cur := s.top 68 | for i < s.size { 69 | items[i] = cur.item 70 | cur = cur.next 71 | i++ 72 | } 73 | 74 | return items 75 | } 76 | 77 | func (s *Stack) String() string { 78 | var ss []string 79 | 80 | for _, v := range s.Iterator() { 81 | ss = append(ss, fmt.Sprint(v)) 82 | } 83 | 84 | return "[" + strings.Join(ss, ", ") + "]" 85 | } 86 | -------------------------------------------------------------------------------- /context/suffix/suffix.go: -------------------------------------------------------------------------------- 1 | package suffix 2 | 3 | // SuffixArrayInterface suffix array API 4 | type SuffixArrayInterface interface { 5 | Length() int 6 | Select(i int) string 7 | Index(i int) int 8 | LCP(i int) int 9 | Rank(key string) int 10 | } 11 | 12 | func LongestRepeatedSubstring(text string) (lrs string) { 13 | sa := NewSuffixArray(text) 14 | lrs = "" 15 | for i := 1; i < sa.Length(); i++ { 16 | longestLen := sa.LCP(i) 17 | if longestLen > len(lrs) { 18 | lrs = sa.Select(i)[0:longestLen] 19 | //lrs = text[sa.Index(i) : sa.Index(i)+longestLen] 20 | } 21 | } 22 | 23 | return "\"" + lrs + "\"" 24 | } 25 | 26 | // LongestCommonSubstring returns the longest common string of the two specified strings 27 | func LongestCommonSubstring(s, t string) (lcs string) { 28 | suffix1 := NewSuffixArray(s) 29 | suffix2 := NewSuffixArray(t) 30 | 31 | // find the longest common substring by "merging" sorted suffixes 32 | lcs = "" 33 | i, j := 0, 0 34 | for i < suffix1.Length() && j < suffix2.Length() { 35 | p := suffix1.Index(i) 36 | q := suffix2.Index(j) 37 | x := lcpFrom(s, t, p, q) 38 | if len(x) > len(lcs) { 39 | lcs = x 40 | } 41 | if compare(s, t, p, q) < 0 { 42 | i++ 43 | } else { 44 | j++ 45 | } 46 | } 47 | 48 | return "\"" + lcs + "\"" 49 | } 50 | 51 | // return the longest common prefix of suffix s[p...] and suffix t[q...] 52 | func lcpFrom(s, t string, p, q int) string { 53 | n := min(len(s)-p, len(t)-q) 54 | for i := 0; i < n; i++ { 55 | if s[p+i] != t[q+i] { 56 | return s[p : p+i] 57 | } 58 | } 59 | return s[p : p+n] 60 | } 61 | 62 | // compare suffix s[p...] and suffix t[q...] 63 | func compare(s, t string, p, q int) int { 64 | pp, qq := len(s)-p, len(t)-q 65 | n := min(pp, qq) 66 | for i := 0; i < n; i++ { 67 | if s[p+i] != t[q+i] { 68 | return int(s[p+i]) - int(t[q+i]) 69 | } 70 | } 71 | 72 | if pp < qq { 73 | return -1 74 | } else if pp > qq { 75 | return +1 76 | } else { 77 | return 0 78 | } 79 | } 80 | 81 | func min(i, j int) int { 82 | if i < j { 83 | return i 84 | } 85 | return j 86 | } 87 | -------------------------------------------------------------------------------- /strings/search/search_test.go: -------------------------------------------------------------------------------- 1 | package search_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/youngzhu/algs4-go/strings/search" 7 | ) 8 | 9 | var testCases = []struct { 10 | pattern, text string 11 | index int 12 | }{ 13 | {"abracadabra", "abacadabrabracabracadabrabrabracad", 14}, 14 | {"rab", "abacadabrabracabracadabrabrabracad", 8}, 15 | {"rabrabracad", "abacadabrabracabracadabrabrabracad", 23}, 16 | {"bcara", "abacadabrabracabracadabrabrabracad", -1}, 17 | {"abacad", "abacadabrabracabracadabrabrabracad", 0}, 18 | } 19 | 20 | func TestBruteForceSearch1(t *testing.T) { 21 | for _, tc := range testCases { 22 | got := BruteForceSearch1(tc.pattern, tc.text) 23 | want := tc.index 24 | 25 | if got != want { 26 | t.Errorf("BruteSearch1(%q, %q) got %d, want %d", tc.pattern, tc.text, got, want) 27 | } 28 | } 29 | } 30 | 31 | func TestBruteForceSearch2(t *testing.T) { 32 | for _, tc := range testCases { 33 | got := BruteForceSearch2(tc.pattern, tc.text) 34 | want := tc.index 35 | 36 | if got != want { 37 | t.Errorf("BruteSearch1(%q, %q) got %d, want %d", tc.pattern, tc.text, got, want) 38 | } 39 | } 40 | } 41 | 42 | func TestRabinKarp(t *testing.T) { 43 | for _, tc := range testCases { 44 | rk := NewRabinKarp(tc.pattern) 45 | got := rk.Search(tc.text) 46 | want := tc.index 47 | 48 | if got != want { 49 | t.Errorf("BruteSearch1(%q, %q) got %d, want %d", tc.pattern, tc.text, got, want) 50 | } 51 | } 52 | } 53 | 54 | func TestKMP(t *testing.T) { 55 | for _, tc := range testCases { 56 | rk := NewKMP(tc.pattern) 57 | got := rk.Search(tc.text) 58 | want := tc.index 59 | 60 | if got != want { 61 | t.Errorf("BruteSearch1(%q, %q) got %d, want %d", tc.pattern, tc.text, got, want) 62 | } 63 | } 64 | } 65 | 66 | func TestBoyerMoore(t *testing.T) { 67 | for _, tc := range testCases { 68 | rk := NewBoyerMoore(tc.pattern) 69 | got := rk.Search(tc.text) 70 | want := tc.index 71 | 72 | if got != want { 73 | t.Errorf("BruteSearch1(%q, %q) got %d, want %d", tc.pattern, tc.text, got, want) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /cmd/context/kwic/kwic.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "flag" 6 | "fmt" 7 | "github.com/youngzhu/algs4-go/context/suffix" 8 | "github.com/youngzhu/algs4-go/testutil" 9 | "os" 10 | "regexp" 11 | ) 12 | 13 | // KWIC: Key Word in Context 14 | // Reads a string from a file specified as the first 15 | // command-line argument; read an integer k specified 16 | // as the second command-line argument; then repeatedly 17 | // processes use queries, printing all occurrences of 18 | // the given query string in the text string with k characters 19 | // of surrounding context on either side. 20 | 21 | var ( 22 | file string 23 | k int 24 | ) 25 | 26 | func init() { 27 | flag.StringVar(&file, "f", "", "file name (path)") 28 | flag.IntVar(&k, "k", 0, "k characters of surrounding context") 29 | } 30 | 31 | // RUN 32 | // go run kwic.go -f testdata/tale.txt.gz -k 10 33 | func main() { 34 | flag.Parse() 35 | 36 | // read in text 37 | in, err := testutil.NewInWithError(file) 38 | if err != nil { 39 | panic(err) 40 | } 41 | text := in.ReadAll() 42 | space := regexp.MustCompile("\\s+") 43 | text = string(space.ReplaceAll([]byte(text), []byte(" "))) 44 | 45 | // build suffix array 46 | sa := suffix.NewSuffixArrayX(text) 47 | 48 | scanner := bufio.NewScanner(os.Stdin) 49 | // find all occurrences of queries and give context 50 | for { 51 | fmt.Print("Enter keyword:") 52 | scanner.Scan() 53 | keyword := scanner.Text() 54 | if keyword == "q" { 55 | os.Exit(0) 56 | } 57 | n := sa.Length() 58 | count := 0 59 | for i := sa.Rank(keyword); i < n; i++ { 60 | from1 := sa.Index(i) 61 | to1 := min(n, from1+len(keyword)) 62 | if keyword != text[from1:to1] { 63 | break 64 | } 65 | from2 := max(0, from1-k) 66 | to2 := min(n, to1+k) 67 | fmt.Println(text[from2:to2]) 68 | count++ 69 | } 70 | fmt.Printf("==\nkeyword:\"%s\", occurrences:%d times", keyword, count) 71 | fmt.Println() 72 | } 73 | } 74 | 75 | func min(i, j int) int { 76 | if i < j { 77 | return i 78 | } 79 | return j 80 | } 81 | 82 | func max(i, j int) int { 83 | if i > j { 84 | return i 85 | } 86 | return j 87 | } 88 | -------------------------------------------------------------------------------- /graphs/digraph/edge_weighted_directed_cycle.go: -------------------------------------------------------------------------------- 1 | package digraph 2 | 3 | // import "log" 4 | import "github.com/youngzhu/algs4-go/fund" 5 | 6 | // Does a given digraph have a directed cycle? 7 | // Solves this problem using depth-first search 8 | 9 | type EdgeWeightedDirectedCycle struct { 10 | marked []bool // marked[v]: has vertex v been marked? 11 | edgeTo []*DirectedEdge // edgeTo[v]: previous vertex on path to v 12 | onStack []bool // onStack[v]: is vertex on the stack? 13 | cycle *fund.Stack // directed cycle (or nil if no such cycle) 14 | } 15 | 16 | func NewEdgeWeightedDirectedCycle(g EdgeWeightedDigraph) *EdgeWeightedDirectedCycle { 17 | marked := make([]bool, g.V()) 18 | edgeTo := make([]*DirectedEdge, g.V()) 19 | onStack := make([]bool, g.V()) 20 | dc := &EdgeWeightedDirectedCycle{marked, edgeTo, onStack, nil} 21 | 22 | for v := 0; v < g.V(); v++ { 23 | if !dc.marked[v] && dc.cycle == nil { 24 | dc.dfs(g, v) 25 | } 26 | } 27 | 28 | return dc 29 | } 30 | 31 | // run DFS and find a directed cycle 32 | // must use pointer (*), otherwise dc.cycle wouldn't change 33 | func (dc *EdgeWeightedDirectedCycle) dfs(g EdgeWeightedDigraph, v int) { 34 | dc.onStack[v] = true 35 | dc.marked[v] = true 36 | 37 | for _, it := range g.Adj(v) { 38 | // short circuit if directed cycle found 39 | if dc.cycle != nil { 40 | return 41 | } 42 | 43 | e := it.(*DirectedEdge) 44 | w := e.To() 45 | 46 | if !dc.marked[w] { // found new vertex, so recur 47 | dc.edgeTo[w] = e 48 | dc.dfs(g, w) 49 | } else if dc.onStack[w] { // trace back directed cycle 50 | cycle := fund.NewStack() 51 | 52 | x := e 53 | for x.From() != w { 54 | cycle.Push(x) 55 | x = dc.edgeTo[x.From()] 56 | } 57 | cycle.Push(x) 58 | // log.Println(w) 59 | dc.cycle = cycle 60 | } 61 | } 62 | 63 | dc.onStack[v] = false 64 | } 65 | 66 | // Does the digraph have a directed cycle? 67 | func (dc *EdgeWeightedDirectedCycle) HasCycle() bool { 68 | return dc.cycle != nil 69 | } 70 | 71 | func (dc *EdgeWeightedDirectedCycle) Cycle() fund.Iterator { 72 | if dc.HasCycle() { 73 | return dc.cycle.Iterator() 74 | } 75 | 76 | return nil 77 | } 78 | -------------------------------------------------------------------------------- /sorting/bench_test.go: -------------------------------------------------------------------------------- 1 | package sorting_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/youngzhu/algs4-go/sorting" 7 | ) 8 | 9 | // go test -v -run="none" -bench="." -benchtime="3s" 10 | 11 | var a = [...]int{9, 10, 0, 7, 8, 4, 3, 6, 2, 1, 5, 5, -99} 12 | 13 | func BenchmarkSelection(b *testing.B) { 14 | soter := NewSelection() 15 | 16 | b.ReportAllocs() 17 | b.ResetTimer() 18 | 19 | for i := 0; i < b.N; i++ { 20 | soter.SortInts(a[0:]) 21 | } 22 | } 23 | 24 | func BenchmarkInsertion(b *testing.B) { 25 | soter := NewInsertion() 26 | 27 | b.ReportAllocs() 28 | b.ResetTimer() 29 | 30 | for i := 0; i < b.N; i++ { 31 | soter.SortInts(a[0:]) 32 | } 33 | } 34 | 35 | func BenchmarkShell(b *testing.B) { 36 | soter := NewShell() 37 | 38 | b.ReportAllocs() 39 | b.ResetTimer() 40 | 41 | for i := 0; i < b.N; i++ { 42 | soter.SortInts(a[0:]) 43 | } 44 | } 45 | 46 | func BenchmarkMerge(b *testing.B) { 47 | soter := NewMerge() 48 | 49 | b.ReportAllocs() 50 | b.ResetTimer() 51 | 52 | for i := 0; i < b.N; i++ { 53 | soter.SortInts(a[0:]) 54 | } 55 | } 56 | 57 | func BenchmarkMergeX(b *testing.B) { 58 | soter := NewMergeX() 59 | 60 | b.ReportAllocs() 61 | b.ResetTimer() 62 | 63 | for i := 0; i < b.N; i++ { 64 | soter.SortInts(a[0:]) 65 | } 66 | } 67 | 68 | func BenchmarkMergeBU(b *testing.B) { 69 | soter := NewMergeBU() 70 | 71 | b.ReportAllocs() 72 | b.ResetTimer() 73 | 74 | for i := 0; i < b.N; i++ { 75 | soter.SortInts(a[0:]) 76 | } 77 | } 78 | 79 | func BenchmarkQuick(b *testing.B) { 80 | soter := NewQuick() 81 | 82 | b.ReportAllocs() 83 | b.ResetTimer() 84 | 85 | for i := 0; i < b.N; i++ { 86 | soter.SortInts(a[0:]) 87 | } 88 | } 89 | 90 | func BenchmarkQuick3way(b *testing.B) { 91 | soter := NewQuick3way() 92 | 93 | b.ReportAllocs() 94 | b.ResetTimer() 95 | 96 | for i := 0; i < b.N; i++ { 97 | soter.SortInts(a[0:]) 98 | } 99 | } 100 | 101 | func BenchmarkHeap(b *testing.B) { 102 | soter := NewHeap() 103 | 104 | b.ReportAllocs() 105 | b.ResetTimer() 106 | 107 | for i := 0; i < b.N; i++ { 108 | soter.SortInts(a[0:]) 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /fund/queue.go: -------------------------------------------------------------------------------- 1 | package fund 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | // FIFO Queue. 9 | // A FIFO queue is a collection that is based on the first-in-first-out (FIFO) 10 | // policy. The policy of doing task in the same order that they arrive is one 11 | // that we encounter frequently in everyday life: from people waiting in line 12 | // at a theater, to cars waiting in line at a toll booth, to tasks waiting to 13 | // be serviced by an application on your computer. 14 | 15 | // Queue implemented using a linked list 16 | type Queue struct { 17 | first *Node // beginning of queue 18 | last *Node // end of queue 19 | size int // number of elements on queue 20 | } 21 | 22 | func NewQueue() *Queue { 23 | return &Queue{} 24 | } 25 | 26 | // Peek returns the item least recently added to the queue 27 | func (q *Queue) Peek() Item { 28 | if q.IsEmpty() { 29 | panic("This queue is empty") 30 | } 31 | return q.first.item 32 | } 33 | 34 | // Enqueue adds the item to the queue 35 | func (q *Queue) Enqueue(item Item) { 36 | oldLast := q.last 37 | q.last = newNode(item, nil) 38 | 39 | if q.IsEmpty() { 40 | q.first = q.last 41 | } else { 42 | oldLast.next = q.last 43 | } 44 | q.size++ 45 | } 46 | 47 | // Dequeue removes and returns the item on this queue that was least recently added 48 | func (q *Queue) Dequeue() Item { 49 | if q.IsEmpty() { 50 | panic("This queue is empty") 51 | } 52 | item := q.first.item 53 | q.first = q.first.next 54 | q.size-- 55 | return item 56 | } 57 | 58 | // Size returns the number of items in this queue 59 | func (q *Queue) Size() int { 60 | return q.size 61 | } 62 | 63 | // IsEmpty return true if the queue is empty 64 | func (q *Queue) IsEmpty() bool { 65 | return q.first == nil 66 | } 67 | 68 | func (q *Queue) Iterator() Iterator { 69 | items := make([]interface{}, q.size) 70 | 71 | i := 0 72 | cur := q.first 73 | for i < q.size { 74 | items[i] = cur.item 75 | cur = cur.next 76 | i++ 77 | } 78 | 79 | return items 80 | } 81 | 82 | func (q *Queue) String() string { 83 | var ss []string 84 | 85 | for _, v := range q.Iterator() { 86 | ss = append(ss, fmt.Sprint(v)) 87 | } 88 | 89 | return "[" + strings.Join(ss, ", ") + "]" 90 | } 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | [![][github-stars-shield]][github-stars-link] 5 | [![][github-forks-shield]][github-forks-link] 6 | [![][github-license-shield]][github-license-link] 7 | 8 | 9 |
10 | 11 | ## Overview 12 | Golang translations of the Java source code 13 | for the algorithms and clients in the textbook Algorithms, 4th Edition by Robert Sedgewick and Kevin Wayne. 14 | 15 | ## Coding style 16 | Try to keep the interface and variable name consistent with the original Java source code while writing idiomatic Go code. 17 | 18 | **Note:** Most clients are in _example_xxx_test.go_. 19 | 20 | ## Index 21 | See [index.md](index.md). 22 | 23 | ## License 24 | This code is released under [GPLv3](LICENSE). 25 | 26 | ## Reference 27 | - https://github.com/kevin-wayne/algs4: The official Java source code repository 28 | - [https://github.com/shellfly/algo](https://github.com/shellfly/algo): Go implementation 29 | - [https://github.com/garyaiki/Scala-Algorithms](https://github.com/garyaiki/Scala-Algorithms): Scala implementation 30 | - [https://github.com/nguyenqthai/Algs4Net](https://github.com/nguyenqthai/Algs4Net): .Net implementation 31 | - [https://github.com/itu-algorithms/itu.algs4](https://github.com/itu-algorithms/itu.algs4): Pthon implementation 32 | - https://github.com/shellfly/algs4-py: Python implementation 33 | 34 | 35 | ## Contribution 36 | Feel free to pull requests or issue reports. Appreciate the contribution of high-quality test cases, code fixes and coding style improvements. 37 | 38 | 39 | [github-forks-link]: https://github.com/youngzhu/algs4-go/network/members 40 | [github-forks-shield]: https://img.shields.io/github/forks/youngzhu/algs4-go?color=8ae8ff&labelColor=black&style=flat-square 41 | [github-license-link]: https://github.com/youngzhu/algs4-go/blob/main/LICENSE 42 | [github-license-shield]: https://img.shields.io/github/license/youngzhu/algs4-go?labelColor=black&style=flat-square 43 | [github-stars-link]: https://github.com/youngzhu/algs4-go/stargazers 44 | [github-stars-shield]: https://img.shields.io/github/stars/youngzhu/algs4-go?color=ffcb47&labelColor=black&style=flat-square 45 | -------------------------------------------------------------------------------- /context/suffix/suffix_array.go: -------------------------------------------------------------------------------- 1 | package suffix 2 | 3 | import ( 4 | "fmt" 5 | "github.com/youngzhu/algs4-go/strings/sort" 6 | ) 7 | 8 | // Suffix sorting: given a string, sort the suffixes of that string in ascending order. 9 | // Resulting sorted list is called a suffix array. 10 | 11 | type SuffixArray struct { 12 | suffixes []string 13 | n int 14 | } 15 | 16 | func NewSuffixArray(txt string) SuffixArray { 17 | n := len(txt) 18 | suffixes := make([]string, n) 19 | for i := 0; i < n; i++ { 20 | suffixes[i] = txt[i:] 21 | } 22 | sort.Quicksort(suffixes) 23 | 24 | return SuffixArray{suffixes: suffixes, n: n} 25 | } 26 | 27 | // Length 28 | // Returns the length of the input string 29 | func (sa SuffixArray) Length() int { 30 | return sa.n 31 | } 32 | 33 | // Index 34 | // Returns the index into the original string of the ith smallest suffix. 35 | func (sa SuffixArray) Index(i int) int { 36 | if i < 0 || i >= sa.n { 37 | panic(`Illegal index: ` + fmt.Sprint(i)) 38 | } 39 | return sa.n - len(sa.suffixes[i]) 40 | } 41 | 42 | // LCP returns the length of the longest common prefix of the ith smallest suffix 43 | // and the i-1 th smallest suffix. 44 | func (sa SuffixArray) LCP(i int) int { 45 | if i < 1 || i >= sa.n { 46 | panic("Illegal argument") 47 | } 48 | return lcp(sa.suffixes[i], sa.suffixes[i-1]) 49 | } 50 | 51 | // longest common prefix of s and t 52 | func lcp(s, t string) int { 53 | n := min(len(s), len(t)) 54 | for i := 0; i < n; i++ { 55 | if s[i] != t[i] { 56 | return i 57 | } 58 | } 59 | return n 60 | } 61 | 62 | // Select 63 | // Returns the ith smallest suffix as a string 64 | func (sa SuffixArray) Select(i int) string { 65 | if i < 0 || i >= sa.n { 66 | panic("Illegal argument") 67 | } 68 | return sa.suffixes[i] 69 | } 70 | 71 | // Rank 72 | // Returns the number of suffixes strictly less than the query string. 73 | // Note: rank(select(i)) == i 74 | func (sa SuffixArray) Rank(query string) int { 75 | lo, hi := 0, sa.n-1 76 | for lo <= hi { 77 | mid := lo + (hi-lo)/2 78 | midSuffix := sa.suffixes[mid] 79 | switch { 80 | case query < midSuffix: 81 | hi = mid - 1 82 | case query > midSuffix: 83 | lo = mid + 1 84 | default: 85 | return mid 86 | } 87 | } 88 | return lo 89 | } 90 | -------------------------------------------------------------------------------- /sorting/pq/example_pq_test.go: -------------------------------------------------------------------------------- 1 | package pq_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/youngzhu/algs4-go/sorting/pq" 7 | ) 8 | 9 | var a = [...]string{"P", "Q", "E", "-", "X", "A", "M", "-", "P", "L", "E", "-"} 10 | 11 | func ExampleMaxPQ() { 12 | p := pq.NewMaxPQ() 13 | 14 | for _, item := range a { 15 | if item != "-" { 16 | p.Insert(pq.StringItem(item)) 17 | } else if !p.IsEmpty() { 18 | fmt.Print(p.Delete(), " ") 19 | } 20 | 21 | } 22 | 23 | fmt.Printf("(%d left on pq)", p.Size()) 24 | 25 | // Output: Q X P (6 left on pq) 26 | } 27 | 28 | func ExampleMinPQ() { 29 | p := pq.NewMinPQ() 30 | 31 | for _, item := range a { 32 | if item != "-" { 33 | p.Insert(pq.StringItem(item)) 34 | } else if !p.IsEmpty() { 35 | fmt.Print(p.Delete(), " ") 36 | } 37 | 38 | } 39 | 40 | fmt.Printf("(%d left on pq)", p.Size()) 41 | 42 | // Output: E A E (6 left on pq) 43 | } 44 | 45 | var ints = []int{2, 4, 7, 6, 8, 11, 17, 15} 46 | 47 | func ExampleMinPQ_Insert() { 48 | q := pq.NewMinPQ() 49 | for _, v := range ints { 50 | q.Insert(pq.IntItem(v)) 51 | } 52 | fmt.Println(q.GetItems()) 53 | 54 | q.Insert(pq.IntItem(3)) 55 | fmt.Println(q.GetItems()) 56 | 57 | // Output: 58 | // [2 4 7 6 8 11 17 15] 59 | // [2 3 7 4 8 11 17 15 6] 60 | } 61 | 62 | func ExampleMinPQ_Delete() { 63 | q := pq.NewMinPQ() 64 | for _, v := range ints { 65 | q.Insert(pq.IntItem(v)) 66 | } 67 | fmt.Println(q.GetItems()) 68 | 69 | q.Delete() 70 | fmt.Println(q.GetItems()) 71 | 72 | // Output: 73 | // [2 4 7 6 8 11 17 15] 74 | // [4 6 7 15 8 11 17] 75 | } 76 | 77 | func ExampleMaxPQ_Insert() { 78 | q := pq.NewMaxPQ() 79 | for _, v := range ints { 80 | q.Insert(pq.IntItem(v)) 81 | } 82 | fmt.Println(q.GetItems()) 83 | 84 | q.Insert(pq.IntItem(3)) 85 | fmt.Println(q.GetItems()) 86 | 87 | // Output: 88 | // [17 15 11 7 6 4 8 2] 89 | // [17 15 11 7 6 4 8 2 3] 90 | } 91 | 92 | func ExampleMaxPQ_Delete() { 93 | q := pq.NewMaxPQ() 94 | for _, v := range ints { 95 | q.Insert(pq.IntItem(v)) 96 | } 97 | fmt.Println(q.GetItems()) 98 | 99 | q.Delete() 100 | fmt.Println(q.GetItems()) 101 | 102 | // Output: 103 | // [17 15 11 7 6 4 8 2] 104 | // [15 7 11 2 6 4 8] 105 | } 106 | -------------------------------------------------------------------------------- /graphs/sp/arbitrage.go: -------------------------------------------------------------------------------- 1 | package sp 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | 7 | "github.com/youngzhu/algs4-go/graphs/digraph" 8 | "github.com/youngzhu/algs4-go/testutil" 9 | ) 10 | 11 | // Arbitrage detection. 12 | // Consider a market for financial transactions that is based on trading commodities. 13 | // The table rates.txt shows conversion rates among currencies. The first line in 14 | // the file is the number V of currencies; then the file has one line per currency, 15 | // giving its name followed by the conversion rates to the other currencies. An 16 | // arbitrage opportunity is a directed cycle such that the product of the exchange 17 | // rates is greater than one. For example, our table says that 1,000 U.S. dollars 18 | // will buy 1,000 x 0.741 = 741 euros, then we can buy 741 x 1.366 = 1,012.206 19 | // Canadian dollars with our euros, and finally, 1,012.206 x 0.995 = 1,007.14497 20 | // U.S. dollars with our Canadian dollars, a 7.14497 dollar profit! 21 | // 22 | // To formulate the arbitrage problem as a negative-cycle detection problem, 23 | // replace each weight by its logarithm, negated. With this change, computing 24 | // path weights by multiplying edge weights in the original problem corresponds 25 | // to adding them in the transformed problem. 26 | 27 | // The routine identifies arbitrage opportunities in a currency-exchange network 28 | // by solving the corresponding negative cycle detection problem. 29 | func Arbitrage(path string) { 30 | in := testutil.NewInReadWords(path) 31 | 32 | n := in.ReadInt() 33 | name := make([]string, n) 34 | 35 | // create complete network 36 | g := digraph.NewEdgeWeightedDigraphN(n) 37 | for v := 0; v < n; v++ { 38 | name[v] = in.ReadString() 39 | for w := 0; w < n; w++ { 40 | rate := in.ReadFloat() 41 | e := digraph.NewDirectedEdge(v, w, -math.Log(rate)) 42 | g.AddEdge(e) 43 | } 44 | } 45 | 46 | // find negative cycle 47 | spt := NewBellmanFordSP(*g, 0) 48 | if spt.HasNegativeCycle() { 49 | stake := 1000.0 50 | for _, edge := range spt.NegativeCycle() { 51 | e := edge.(*digraph.DirectedEdge) 52 | fmt.Printf("%10.5f %s ", stake, name[e.From()]) 53 | stake = stake * math.Exp(-e.Weight()) 54 | fmt.Printf("= %10.5f %s\n", stake, name[e.To()]) 55 | } 56 | } else { 57 | fmt.Println("No arbitrage opportunity") 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /fund/uf/uf.go: -------------------------------------------------------------------------------- 1 | package uf 2 | 3 | // UF is a weighted quick-union by rank with path compression by halving. 4 | // There are a number of easy ways to improve the weighted quick-union algorithm 5 | // further. Ideally, we would like every node to link directly to the root of 6 | // its tree, but we do not want to pay the price of changing a large number of 7 | // links. We can approach the ideal simply by making all the nodes that we do 8 | // examine directly link to the root. 9 | type UF struct { 10 | parent []int // parent[i]: parent of i 11 | rank []byte // rank[i]: rank of subtree rooted at i (never more than 31) 12 | count int // number of components 13 | } 14 | 15 | // NewUF returns an empty union-find data structure with n elements (0...n-1) 16 | // Initially, each element is in its own set. 17 | func NewUF(n int) *UF { 18 | if n < 0 { 19 | panic("n must be positive") 20 | } 21 | 22 | parent := make([]int, n) 23 | rank := make([]byte, n) 24 | for i := 0; i < n; i++ { 25 | parent[i] = i 26 | rank[i] = 0 27 | } 28 | 29 | return &UF{parent, rank, n} 30 | } 31 | 32 | // Union merges the set containing element p with the set contain element q 33 | func (u *UF) Union(p, q int) { 34 | rootP := u.Find(p) 35 | rootQ := u.Find(q) 36 | if rootP == rootQ { 37 | return 38 | } 39 | 40 | // make root of smaller rank point to root of larger rank 41 | if u.rank[rootP] < u.rank[rootQ] { 42 | u.parent[rootP] = rootQ 43 | } else if u.rank[rootP] > u.rank[rootQ] { 44 | u.parent[rootQ] = rootP 45 | } else { 46 | u.parent[rootQ] = rootP 47 | u.rank[rootP]++ 48 | } 49 | 50 | u.count-- 51 | } 52 | 53 | // Find returns the canonical element of the set containing element p 54 | func (u *UF) Find(p int) int { 55 | u.validate(p) 56 | for p != u.parent[p] { 57 | u.parent[p] = u.parent[u.parent[p]] // path compression by halving 58 | p = u.parent[p] 59 | } 60 | return p 61 | } 62 | 63 | // Count returns the number of sets 64 | func (u *UF) Count() int { 65 | return u.count 66 | } 67 | 68 | // Connected returns true if the two elements are in the same set 69 | func (u *UF) Connected(p, q int) bool { 70 | return u.Find(p) == u.Find(q) 71 | } 72 | 73 | // validate that p is a valid index 74 | func (u UF) validate(p int) { 75 | n := len(u.parent) 76 | if p < 0 || p >= n { 77 | panic("invalid index") 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /cmd/context/kwicx/kwicx.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "flag" 6 | "fmt" 7 | "github.com/youngzhu/algs4-go/context/suffix" 8 | "github.com/youngzhu/algs4-go/testutil" 9 | "os" 10 | "regexp" 11 | ) 12 | 13 | // For rune 14 | 15 | // KWIC: Key Word in Context 16 | // Reads a string from a file specified as the first 17 | // command-line argument; read an integer k specified 18 | // as the second command-line argument; then repeatedly 19 | // processes use queries, printing all occurrences of 20 | // the given query string in the text string with k characters 21 | // of surrounding context on either side. 22 | 23 | var ( 24 | file string 25 | k int 26 | ) 27 | 28 | func init() { 29 | flag.StringVar(&file, "f", "", "file name (path)") 30 | flag.IntVar(&k, "k", 0, "k characters of surrounding context") 31 | } 32 | 33 | // RUN 34 | // go run kwicx.go -f testdata/tale.txt.gz -k 10 35 | // go run kwicx.go -f testdata/rune.txt -k 10 36 | // go run kwicx.go -f testdata/sgyy.txt -k 10 37 | func main() { 38 | flag.Parse() 39 | 40 | // read in text 41 | in, err := testutil.NewInWithError(file) 42 | if err != nil { 43 | panic(err) 44 | } 45 | text := in.ReadAll() 46 | space := regexp.MustCompile("\\s+") 47 | text = string(space.ReplaceAll([]byte(text), []byte(" "))) 48 | 49 | // build suffix array 50 | sa := suffix.NewSuffixArrayRune(text) 51 | 52 | txtRune := []rune(text) 53 | 54 | scanner := bufio.NewScanner(os.Stdin) 55 | // find all occurrences of queries and give context 56 | for { 57 | fmt.Print("Enter keyword:") 58 | scanner.Scan() 59 | keyword := scanner.Text() 60 | if keyword == "q" { 61 | os.Exit(0) 62 | } 63 | runeLen := len([]rune(keyword)) 64 | n := sa.Length() 65 | count := 0 66 | for i := sa.Rank(keyword); i < n; i++ { 67 | from1 := sa.Index(i) 68 | to1 := min(n, from1+runeLen) 69 | if keyword != string(txtRune[from1:to1]) { 70 | break 71 | } 72 | from2 := max(0, from1-k) 73 | to2 := min(n, to1+k) 74 | fmt.Println(string(txtRune[from2:to2])) 75 | count++ 76 | } 77 | fmt.Printf("==\nkeyword:\"%s\", occurrences:%d times", keyword, count) 78 | fmt.Println() 79 | } 80 | } 81 | 82 | func min(i, j int) int { 83 | if i < j { 84 | return i 85 | } 86 | return j 87 | } 88 | 89 | func max(i, j int) int { 90 | if i > j { 91 | return i 92 | } 93 | return j 94 | } 95 | -------------------------------------------------------------------------------- /graphs/digraph/kosaraju_sharir_scc.go: -------------------------------------------------------------------------------- 1 | package digraph 2 | 3 | // Strong connectivity is an equivalence relation on the set of vertices: 4 | // Reflexive: Every vertex v is strongly connected to itself 5 | // Symmetric: If v is strongly connected to w, then w is strongly connected to v 6 | // Transtive: If v is strongly connected to w and w is strongly connected to x, 7 | // then v is also strongly connected to x 8 | 9 | // implements as follows: 10 | // 1. Given a digraph G, use DepthFirstOrder to compute the reverse postorder of its reverse 11 | // 2. Run standard DFS on G, but consider the unmarked vertices in the order 12 | // just computed instead of the standard numerical order 13 | // 3. All vertices reached on a call to the recursive dfs() from New method 14 | 15 | type KosarajuSharirSCC struct { 16 | digraph Digraph 17 | marked []bool // marked[v]: has vertex v been visited? 18 | id []int // id[v]: id of strong component containing v 19 | count int // number of strongly-connected components 20 | } 21 | 22 | func NewKosarajuSharirSCC(g Digraph) KosarajuSharirSCC { 23 | // compute reverse postorder of reverse graph 24 | dfo := NewDepthFirstOrder(g.Reverse()) 25 | 26 | marked := make([]bool, g.V()) 27 | id := make([]int, g.V()) 28 | 29 | scc := &KosarajuSharirSCC{digraph: g, marked: marked, id: id} 30 | 31 | // run DFS on g, using reverse postorder to guide calulation 32 | for _, v := range dfo.ReversePostorder() { 33 | i := v.(int) 34 | if !scc.marked[i] { 35 | scc.dfs(i) 36 | scc.count++ 37 | } 38 | } 39 | 40 | return *scc 41 | } 42 | 43 | func (scc *KosarajuSharirSCC) dfs(v int) { 44 | scc.marked[v] = true 45 | scc.id[v] = scc.count 46 | for _, it := range scc.digraph.Adj(v) { 47 | w := it.(int) 48 | if !scc.marked[w] { 49 | scc.dfs(w) 50 | } 51 | } 52 | } 53 | 54 | // Returns the number of strong components 55 | func (scc KosarajuSharirSCC) Count() int { 56 | return scc.count 57 | } 58 | 59 | // Are vertices v and w in the same strong component? 60 | func (scc KosarajuSharirSCC) StronglyConnected(v, w int) bool { 61 | scc.digraph.validateVertex(v) 62 | scc.digraph.validateVertex(w) 63 | return scc.id[v] == scc.id[w] 64 | } 65 | 66 | // Returns the component id of the strong component containing vertex v 67 | func (scc KosarajuSharirSCC) Id(v int) int { 68 | scc.digraph.validateVertex(v) 69 | return scc.id[v] 70 | } -------------------------------------------------------------------------------- /fund/xsum/xsum_test.go: -------------------------------------------------------------------------------- 1 | package xsum_test 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "testing" 7 | 8 | . "github.com/youngzhu/algs4-go/fund/xsum" 9 | "github.com/youngzhu/algs4-go/testutil" 10 | ) 11 | 12 | func readInts(path string) []int { 13 | in := testutil.NewInReadWords(path) 14 | return in.ReadAllInts() 15 | } 16 | 17 | var ints1K = readInts("testdata/1Kints.txt") 18 | var ints2K = readInts("testdata/2Kints.txt.gz") 19 | var ints4K = readInts("testdata/4Kints.txt.gz") 20 | 21 | func TestMain(m *testing.M) { 22 | log.Println("before..") 23 | 24 | r := m.Run() 25 | 26 | log.Println("after...") 27 | 28 | os.Exit(r) 29 | } 30 | 31 | func TestThreeSumCount(t *testing.T) { 32 | // t.Parallel() 33 | 34 | want := []int{70, 528, 4039} 35 | 36 | got := []int{ 37 | ThreeSumCount(ints1K), 38 | ThreeSumCount(ints2K), 39 | ThreeSumCount(ints4K), 40 | } 41 | 42 | for i, v := range want { 43 | if got[i] != v { 44 | t.Errorf("got: %v; want: %v", got, want) 45 | } 46 | } 47 | } 48 | 49 | func TestThreeSumCountFast(t *testing.T) { 50 | // t.Parallel() 51 | 52 | want := []int{70, 528, 4039} 53 | 54 | got := []int{ 55 | ThreeSumCountFast(ints1K), 56 | ThreeSumCountFast(ints2K), 57 | ThreeSumCountFast(ints4K), 58 | } 59 | 60 | for i, v := range want { 61 | if got[i] != v { 62 | t.Errorf("got: %v; want: %v", got, want) 63 | } 64 | } 65 | } 66 | 67 | func TestTwoSumCount(t *testing.T) { 68 | // t.Parallel() 69 | 70 | want := []int{1, 2, 3} 71 | 72 | got := []int{ 73 | TwoSumCount(ints1K), 74 | TwoSumCount(ints2K), 75 | TwoSumCount(ints4K), 76 | } 77 | 78 | for i, v := range want { 79 | if got[i] != v { 80 | t.Errorf("got: %v; want: %v", got, want) 81 | } 82 | } 83 | 84 | } 85 | 86 | func TestTwoSumCountFast(t *testing.T) { 87 | // t.Parallel() 88 | 89 | want := []int{1, 2, 3} 90 | 91 | got := []int{ 92 | TwoSumCountFast(ints1K), 93 | TwoSumCountFast(ints2K), 94 | TwoSumCountFast(ints4K), 95 | } 96 | 97 | for i, v := range want { 98 | if got[i] != v { 99 | t.Errorf("got: %v; want: %v", got, want) 100 | } 101 | } 102 | 103 | } 104 | 105 | // go test -v 106 | // TestThreeSumCount (12.18s) 107 | // TestThreeSumCountFast (0.40s) 108 | // TestTwoSumCount (0.01s) 109 | // TestTwoSumCountFast (0.00s) 110 | -------------------------------------------------------------------------------- /graphs/sp/acyclic_sp.go: -------------------------------------------------------------------------------- 1 | package sp 2 | 3 | import ( 4 | "github.com/youngzhu/algs4-go/fund" 5 | "github.com/youngzhu/algs4-go/graphs" 6 | "github.com/youngzhu/algs4-go/graphs/digraph" 7 | ) 8 | 9 | // Computes shortest paths in an edge-weighted acyclic digraph 10 | type AcyclicSP struct { 11 | graph digraph.EdgeWeightedDigraph 12 | source int 13 | distTo []graphs.Distance // distTo[v]: distance of shortest s->v path 14 | edgeTo []*digraph.DirectedEdge // edgeTo[v]: last edge on shortest s->v path 15 | } 16 | 17 | func NewAcyclicSP(g digraph.EdgeWeightedDigraph, s int) *AcyclicSP { 18 | n := g.V() 19 | distTo := make([]graphs.Distance, n) 20 | edgeTo := make([]*digraph.DirectedEdge, n) 21 | 22 | asp := &AcyclicSP{g, s, distTo, edgeTo} 23 | 24 | asp.validateVertex(s) 25 | 26 | for i := 0; i < n; i++ { 27 | distTo[i] = graphs.DistanceInfinity 28 | } 29 | distTo[s] = graphs.DistanceZero 30 | 31 | // visit vertices in topological order 32 | topo := digraph.NewTopologicalWeighted(g) 33 | if !topo.HasOrder() { 34 | panic("digraph is not acyclic") 35 | } 36 | for _, v := range topo.Order() { 37 | for _, edge := range g.Adj(v) { 38 | e := edge.(*digraph.DirectedEdge) 39 | asp.relax(e) 40 | } 41 | } 42 | 43 | return asp 44 | } 45 | 46 | // relax edge e 47 | func (asp *AcyclicSP) relax(e *digraph.DirectedEdge) { 48 | v, w := e.From(), e.To() 49 | distance := graphs.Distance(e.Weight()) 50 | if asp.distTo[w] > asp.distTo[v]+distance { 51 | asp.distTo[w] = asp.distTo[v] + distance 52 | asp.edgeTo[w] = e 53 | } 54 | } 55 | 56 | // Returns the length of a shortest path from the source vertex s to vertex v 57 | func (asp AcyclicSP) DistTo(v int) float64 { 58 | asp.validateVertex(v) 59 | return float64(asp.distTo[v]) 60 | } 61 | 62 | // HasPathTo return true if there is a path from the source vertex to vertx v 63 | func (asp AcyclicSP) HasPathTo(v int) bool { 64 | asp.validateVertex(v) 65 | return asp.distTo[v] < graphs.DistanceInfinity 66 | } 67 | 68 | // Returns a shortest path from the source vertex to vertex v 69 | func (asp *AcyclicSP) PathTo(v int) fund.Iterator { 70 | asp.validateVertex(v) 71 | stack := fund.NewStack() 72 | 73 | if asp.HasPathTo(v) { 74 | for e := asp.edgeTo[v]; e != nil; e = asp.edgeTo[e.From()] { 75 | stack.Push(e) 76 | } 77 | } 78 | 79 | return stack.Iterator() 80 | } 81 | 82 | func (t *AcyclicSP) validateVertex(v int) { 83 | if v < 0 || v >= len(t.distTo) { 84 | panic("invalidate vertex") 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /graphs/digraph/breadth_first_directed_paths.go: -------------------------------------------------------------------------------- 1 | package digraph 2 | 3 | import ( 4 | "github.com/youngzhu/algs4-go/graphs" 5 | "github.com/youngzhu/algs4-go/fund" 6 | ) 7 | 8 | type BreadthFirstDirectedPaths struct { 9 | graph Digraph 10 | source int // source vertex 11 | marked []bool // marked[v]: is there an s-v path? 12 | edgeTo []int // edgeTo[v]: previous edge on shortest s-v path 13 | distTo []int // distTo[v]: number of edges on shortest s-v path 14 | } 15 | 16 | // Computes the shortest path between the source vertex (s) 17 | // and every other vertex in graph g 18 | func NewBreadthFirstDirectedPaths(g Digraph, s int) BreadthFirstDirectedPaths { 19 | g.validateVertex(s) 20 | 21 | marked := make([]bool, g.V()) 22 | edgeTo := make([]int, g.V()) 23 | distTo := make([]int, g.V()) 24 | 25 | for v := 0; v < g.V(); v++ { 26 | distTo[v] = graphs.InfinityDistance 27 | } 28 | 29 | path := BreadthFirstDirectedPaths{g, s, marked, edgeTo, distTo} 30 | path.bfs() 31 | 32 | return path 33 | } 34 | 35 | // breadth first search from s 36 | func (p BreadthFirstDirectedPaths) bfs() { 37 | queue := fund.NewQueue() 38 | 39 | p.marked[p.source] = true 40 | p.distTo[p.source] = 0 41 | queue.Enqueue(fund.Item(p.source)) 42 | 43 | for !queue.IsEmpty() { 44 | v := queue.Dequeue().(int) 45 | 46 | for _, it := range p.graph.Adj(v) { 47 | w := it.(int) 48 | if !p.marked[w] { 49 | p.marked[w] = true 50 | p.edgeTo[w] = v 51 | p.distTo[w] = p.distTo[v] + 1 52 | queue.Enqueue(fund.Item(w)) 53 | } 54 | } 55 | } 56 | } 57 | 58 | // Is there a path between the source vertex (s) and vertex (v) 59 | func (p BreadthFirstDirectedPaths) HasPathTo(v int) bool { 60 | p.graph.validateVertex(v) 61 | return p.marked[v] 62 | } 63 | 64 | // Returns the number of edges in a shortest path between the source vertex s 65 | // and vertex v 66 | func (p BreadthFirstDirectedPaths) DistTo(v int) int { 67 | p.graph.validateVertex(v) 68 | return p.distTo[v] 69 | } 70 | 71 | // Returns a path between the source vertex (s) and vertex v 72 | // or nil if no such path 73 | func (p BreadthFirstDirectedPaths) PathTo(v int) []int { 74 | if !p.HasPathTo(v) { 75 | return nil 76 | } 77 | 78 | stack := fund.NewStack() 79 | 80 | for x := v; x != p.source; x = p.edgeTo[x] { 81 | stack.Push(fund.Item(x)) 82 | } 83 | stack.Push(fund.Item(p.source)) 84 | 85 | path := make([]int, stack.Size()) 86 | i := 0 87 | for !stack.IsEmpty() { 88 | path[i] = stack.Pop().(int) 89 | i++ 90 | } 91 | 92 | return path 93 | } -------------------------------------------------------------------------------- /graphs/mst/example_test.go: -------------------------------------------------------------------------------- 1 | package mst_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/youngzhu/algs4-go/graphs/mst" 7 | "github.com/youngzhu/algs4-go/testutil" 8 | ) 9 | 10 | var ( 11 | tinyEWG, mediumEWG *mst.EdgeWeightedGraph 12 | ) 13 | 14 | func init() { 15 | in := testutil.NewInReadWords("testdata/tinyEWG.txt") 16 | tinyEWG = mst.NewEdgeWeightedGraphIn(in) 17 | 18 | in = testutil.NewInReadWords("testdata/mediumEWG.txt.gz") 19 | mediumEWG = mst.NewEdgeWeightedGraphIn(in) 20 | } 21 | 22 | func ExampleEdgeWeightedGraph() { 23 | 24 | fmt.Print(tinyEWG) 25 | 26 | // Output: 27 | // vertices:8, edges:16 28 | // 0: 6-0 0.58000 0-2 0.26000 0-4 0.38000 0-7 0.16000 29 | // 1: 1-3 0.29000 1-2 0.36000 1-7 0.19000 1-5 0.32000 30 | // 2: 6-2 0.40000 2-7 0.34000 1-2 0.36000 0-2 0.26000 2-3 0.17000 31 | // 3: 3-6 0.52000 1-3 0.29000 2-3 0.17000 32 | // 4: 6-4 0.93000 0-4 0.38000 4-7 0.37000 4-5 0.35000 33 | // 5: 1-5 0.32000 5-7 0.28000 4-5 0.35000 34 | // 6: 6-4 0.93000 6-0 0.58000 3-6 0.52000 6-2 0.40000 35 | // 7: 2-7 0.34000 1-7 0.19000 0-7 0.16000 5-7 0.28000 4-7 0.37000 36 | } 37 | 38 | func ExampleLazyPrimMST_tinyEWG() { 39 | mst := mst.NewLazyPrimMST(*tinyEWG) 40 | 41 | for _, e := range mst.Edges() { 42 | fmt.Println(e) 43 | } 44 | 45 | fmt.Printf("%.5f\n", mst.Weight()) 46 | 47 | // Output: 48 | // 0-7 0.16000 49 | // 1-7 0.19000 50 | // 0-2 0.26000 51 | // 2-3 0.17000 52 | // 5-7 0.28000 53 | // 4-5 0.35000 54 | // 6-2 0.40000 55 | // 1.81000 56 | } 57 | 58 | func ExampleLazyPrimMST_mediumEWG() { 59 | mst := mst.NewLazyPrimMST(*mediumEWG) 60 | 61 | for _, e := range mst.Edges() { 62 | fmt.Println(e) 63 | } 64 | 65 | fmt.Printf("%.5f\n", mst.Weight()) 66 | } 67 | 68 | func ExamplePrimMST_tinyEWG() { 69 | mst := mst.NewPrimMST(*tinyEWG) 70 | 71 | for _, e := range mst.Edges() { 72 | fmt.Println(e) 73 | } 74 | 75 | fmt.Printf("%.5f\n", mst.Weight()) 76 | 77 | // Output: 78 | // 1-7 0.19000 79 | // 0-2 0.26000 80 | // 2-3 0.17000 81 | // 4-5 0.35000 82 | // 5-7 0.28000 83 | // 6-2 0.40000 84 | // 0-7 0.16000 85 | // 1.81000 86 | } 87 | 88 | func ExampleKruskalMST() { 89 | mst := mst.NewKruskalMST(*tinyEWG) 90 | 91 | for _, e := range mst.Edges() { 92 | fmt.Println(e) 93 | } 94 | 95 | fmt.Printf("%.5f\n", mst.Weight()) 96 | 97 | // Output: 98 | // 0-7 0.16000 99 | // 2-3 0.17000 100 | // 1-7 0.19000 101 | // 0-2 0.26000 102 | // 5-7 0.28000 103 | // 4-5 0.35000 104 | // 6-2 0.40000 105 | // 1.81000 106 | } 107 | -------------------------------------------------------------------------------- /graphs/sp/cpm.go: -------------------------------------------------------------------------------- 1 | package sp 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/youngzhu/algs4-go/graphs/digraph" 7 | "github.com/youngzhu/algs4-go/testutil" 8 | ) 9 | 10 | // Critical path method. 11 | // We consider the parallel precedence-constrained job scheduling problem: Given 12 | // a set of jobs of specified duration to be completed, with precedence constraints 13 | // that specify that certain jobs have to be completed before certain other jobs 14 | // are begun, how can we schedule the jobs on identical processors (as many as needed) 15 | // such that they are all completed in the minimum amount of time while still 16 | // respecting the constrains? 17 | // 18 | // This problem can be solved by formulating it as a longest paths problem in an 19 | // edge-weighted DAG: Create an edge-weighted DAG with a source a, a sink t, and 20 | // two vertices for each job (a start vertex and an end vertex). For each job, 21 | // add an edge from its start vertex to its end vertex with weight equal to its 22 | // duration. For each precedence constrain v->w, add a zero-weight edge from the 23 | // end vertex corresponding to v to the beginning vertex corresponding to w. Also 24 | // add zero-weight edges from the source to each job's start vertex and from each 25 | // job's end vertex to the sink. 26 | // Now, schedule each job at the time given by the length of its longest path 27 | // from the source. 28 | 29 | // Reads the precedence constraints from file 30 | // and prints a feasible schedule. 31 | func CPM(path string) { 32 | in := testutil.NewInReadWords(path) 33 | 34 | // number of jobs 35 | n := in.ReadInt() 36 | 37 | // source and sink 38 | source, sink := 2*n, 2*n+1 39 | 40 | // build network 41 | g := digraph.NewEdgeWeightedDigraphN(2*n + 2) 42 | for i := 0; i < n; i++ { 43 | duration := in.ReadFloat() 44 | g.AddEdge(digraph.NewDirectedEdge(source, i, 0)) 45 | g.AddEdge(digraph.NewDirectedEdge(i+n, sink, 0)) 46 | g.AddEdge(digraph.NewDirectedEdge(i, i+n, duration)) 47 | 48 | // precedence constraints 49 | m := in.ReadInt() 50 | for j := 0; j < m; j++ { 51 | precedent := in.ReadInt() 52 | g.AddEdge(digraph.NewDirectedEdge(n+i, precedent, 0)) 53 | } 54 | } 55 | 56 | // compute longest path 57 | lp := NewAcyclicLP(*g, source) 58 | 59 | // print results 60 | columns := []string{"job", "start", "finish"} 61 | fmt.Printf("%4s %8s %8s\n", columns[0], columns[1], columns[2]) 62 | fmt.Println("--------------------") 63 | for i := 0; i < n; i++ { 64 | fmt.Printf("%4d %7.1f %7.1f\n", i, lp.DistTo(i), lp.DistTo(i+n)) 65 | } 66 | 67 | fmt.Printf("Finish time: %7.1f\n", lp.DistTo(sink)) 68 | } 69 | -------------------------------------------------------------------------------- /graphs/digraph/symbol_digraph.go: -------------------------------------------------------------------------------- 1 | package digraph 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/youngzhu/algs4-go/searching" 7 | "github.com/youngzhu/algs4-go/testutil" 8 | ) 9 | 10 | type SymbolDigraph struct { 11 | st searching.RedBlackBST // string -> index 12 | keys []string // index -> string 13 | digraph *Digraph // the underlying digraph 14 | } 15 | 16 | // New a Symbol Digraph from a file using the specified delimiter. 17 | // Each line in the file contains the name of a vertex, 18 | // followed by a list of the names of the vertices adjacent to that vertex, 19 | // separated by the delimiter. 20 | func NewSymbolDigraph(filepath, delimiter string) SymbolDigraph { 21 | st := searching.NewRedBlackBST() 22 | 23 | // first pass builds the index by reading strings to associate 24 | // distinct strings with an index 25 | in := testutil.NewInReadLines(filepath) 26 | for in.HasNext() { 27 | slice := strings.Split(in.ReadLine(), delimiter) 28 | for _, v := range slice { 29 | key := searching.StringKey(v) 30 | if !st.Contains(key) { 31 | st.Put(key, st.Size()) 32 | } 33 | } 34 | } 35 | 36 | // inverted index to get string keys in an array 37 | keys := make([]string, st.Size()) 38 | for _, k := range st.Keys() { 39 | i := st.Get(k).(int) 40 | keys[i] = string(k.(searching.StringKey)) 41 | } 42 | 43 | // second pass builds the digraph by connecting first vertex 44 | // on each line to all others 45 | digraph := NewDigraphN(st.Size()) 46 | in = testutil.NewIn(filepath) 47 | for in.HasNext() { 48 | slice := strings.Split(in.ReadLine(), delimiter) 49 | key := searching.StringKey(slice[0]) 50 | v := st.Get(key).(int) // first vertex 51 | var w int 52 | for _, str := range slice[1:] { 53 | key = searching.StringKey(str) 54 | w = st.Get(key).(int) 55 | digraph.AddEdge(v, w) 56 | } 57 | } 58 | 59 | return SymbolDigraph{*st, keys, digraph} 60 | } 61 | 62 | // Does the digraph contain the vertex named s 63 | func (sg SymbolDigraph) Contains(s string) bool { 64 | key := searching.StringKey(s) 65 | return sg.st.Contains(key) 66 | } 67 | 68 | // Returns the integer associated with the vertex named s 69 | func (sg SymbolDigraph) Index(s string) int { 70 | key := searching.StringKey(s) 71 | return sg.st.Get(key).(int) 72 | } 73 | 74 | // Returns the name of the vertex associated with the integer v 75 | func (sg SymbolDigraph) Name(v int) string { 76 | sg.digraph.validateVertex(v) 77 | return sg.keys[v] 78 | } 79 | 80 | // Returns the digraph associated with the symbol digraph 81 | func (sg SymbolDigraph) Digraph() *Digraph { 82 | return sg.digraph 83 | } 84 | -------------------------------------------------------------------------------- /graphs/digraph/topological.go: -------------------------------------------------------------------------------- 1 | package digraph 2 | 3 | // Topological sort. 4 | // Given a digraph, put the vertices in order such that all its directed edges 5 | // point from a vertex earlier in the order to a vertex later in the order (or 6 | // report that doing so is not possible). 7 | // Remarkably, a reverse postorder in a DAG provides a topological order. 8 | 9 | // A digraph has a topological order if and only if it is a DAG. 10 | // Reverse postorder in a DAG is a topological sort. 11 | // With depth-first search, we can topologically sort a DAG in time proportional to V+E. 12 | 13 | type Topological struct { 14 | order []int // topological order 15 | rank []int // rank[v]: rank of vertex v in order 16 | } 17 | 18 | func NewTopological(g IDigraph) Topological { 19 | t := Topological{} 20 | 21 | finder := NewDirectedCycle(g) 22 | if !finder.HasCycle() { 23 | dfo := NewDepthFirstOrder(g) 24 | order := dfo.ReversePostorder() 25 | rank := make([]int, g.V()) 26 | 27 | for i, v := range order { 28 | rank[v.(int)] = i 29 | } 30 | 31 | orderInt := make([]int, len(order)) 32 | for i, v := range order { 33 | orderInt[i] = v.(int) 34 | } 35 | 36 | t.order = orderInt 37 | t.rank = rank 38 | } 39 | 40 | return t 41 | } 42 | 43 | func NewTopologicalWeighted(g EdgeWeightedDigraph) Topological { 44 | t := Topological{} 45 | 46 | finder := NewEdgeWeightedDirectedCycle(g) 47 | if !finder.HasCycle() { 48 | dfo := NewDepthFirstOrderWeighted(g) 49 | order := dfo.ReversePostorder() 50 | rank := make([]int, g.V()) 51 | 52 | for i, v := range order { 53 | rank[v.(int)] = i 54 | } 55 | 56 | orderInt := make([]int, len(order)) 57 | for i, v := range order { 58 | orderInt[i] = v.(int) 59 | } 60 | 61 | t.order = orderInt 62 | t.rank = rank 63 | } 64 | 65 | return t 66 | } 67 | 68 | // Returns a topological order if the digraph has a topologial order 69 | func (t Topological) Order() []int { 70 | return t.order 71 | } 72 | 73 | // Does the digraph have a topological order 74 | func (t Topological) HasOrder() bool { 75 | return t.order != nil 76 | } 77 | 78 | // Does the digraph is a DAG 79 | // equivalently, does have a topological order 80 | func (t Topological) IsDAG() bool { 81 | return t.HasOrder() 82 | } 83 | 84 | // The rank of vertex v in the topological order 85 | // return -1, if the digraph is not a DAG 86 | func (t Topological) Rank(v int) int { 87 | t.validateVertex(v) 88 | if t.HasOrder() { 89 | return t.rank[v] 90 | } 91 | return -1 92 | } 93 | 94 | func (t Topological) validateVertex(v int) { 95 | if v < 0 || v >= len(t.rank) { 96 | panic("invalidate vertex") 97 | } 98 | } -------------------------------------------------------------------------------- /sorting/quick_3way.go: -------------------------------------------------------------------------------- 1 | package sorting 2 | 3 | // Entropy-optimal sorting. 4 | // Arrays with large numbers of duplicate sort keys arise frequently in applications. 5 | // In such applications, there is potential to reduce the time of the sort from 6 | // linearithmic to linear. 7 | 8 | // One straightforward idea is to partition the array into three parts, one each 9 | // for items with keys smaller than, equal to, and larger than the partitioning 10 | // item's key. Accomplishing this partitioning was a classical programming exercise 11 | // popularized by E.W.Dijkstra as the Dutch National Flag problem, because it is 12 | // like sorting an array with three possible key values, which might correspond to 13 | // the three colors on the flag. 14 | 15 | // Dijkstra's solution is based on a single left-to-right pass through the array 16 | // that maintains a pointer lt such that a[lo..lt-1] is less than v, a pointer gt 17 | // such that a[gt+1..hi] is greater than v, and a pointer i such that a[lt..i-1] 18 | // are equal to v, and a[i..gt] are not yet examined. 19 | 20 | func Quicksort3way(x Sortable) { 21 | // for (mostly) ordered items, shuffle is important 22 | shuffle(x) 23 | 24 | quicksort3way(x, 0, x.Len()-1) 25 | } 26 | 27 | // quicksort the subarray from x[lo] to x[hi] using 3-way partitioning 28 | func quicksort3way(x Sortable, lo, hi int) { 29 | if hi <= lo { 30 | return 31 | } 32 | 33 | lt, gt := partition3way(x, lo, hi) 34 | 35 | // x[lo..lt-1] < a[lt..gt] < a[gt+1..hi] 36 | quicksort3way(x, lo, lt-1) 37 | quicksort3way(x, gt+1, hi) 38 | } 39 | 40 | // Starting with i equal to lo+1 we process a[i] using the 3-way compare to handle 41 | // the three possible cases: 42 | // a[i] less than v: exchange a[lt] with a[i] and increment both lt and i 43 | // a[i] greater than v: exchange a[i] with a[gt] and decrement gt 44 | // a[i] equal to v: increment i 45 | func partition3way(x Sortable, lo, hi int) (int, int) { 46 | i := lo + 1 47 | lt, gt := lo, hi 48 | 49 | // x[lt] === x[lo] 50 | for i <= gt { 51 | if x.Less(i, lt) { 52 | x.Swap(i, lt) 53 | lt++ 54 | i++ 55 | } else if x.Less(lt, i) { 56 | x.Swap(i, gt) 57 | gt-- 58 | } else { 59 | i++ 60 | } 61 | } 62 | 63 | return lt, gt 64 | } 65 | 66 | type Quick3way struct{} 67 | 68 | func NewQuick3way() Sorter { 69 | return Quick3way{} 70 | } 71 | 72 | // Implements Sorter 73 | 74 | func (s Quick3way) SortInts(x []int) { 75 | Quicksort3way(IntSortSlice(x)) 76 | } 77 | func (s Quick3way) SortFloat64s(x []float64) { 78 | Quicksort3way(Float64SortSlice(x)) 79 | } 80 | func (s Quick3way) SortStrings(x []string) { 81 | Quicksort3way(StringSortSlice(x)) 82 | } 83 | -------------------------------------------------------------------------------- /graphs/sp/acyclic_lp.go: -------------------------------------------------------------------------------- 1 | package sp 2 | 3 | import ( 4 | "github.com/youngzhu/algs4-go/fund" 5 | "github.com/youngzhu/algs4-go/graphs" 6 | "github.com/youngzhu/algs4-go/graphs/digraph" 7 | ) 8 | 9 | // Single-source longest paths problem in edge-weighted DAGs. 10 | // We can solve the problem by initializing the distTo[] values to negative 11 | // infinity and switching the sense of the inequality in relax(). 12 | type AcyclicLP struct { 13 | graph digraph.EdgeWeightedDigraph 14 | source int 15 | distTo []graphs.Distance // distTo[v]: distance of longest s->v path 16 | edgeTo []*digraph.DirectedEdge // edgeTo[v]: last edge on longest s->v path 17 | } 18 | 19 | func NewAcyclicLP(g digraph.EdgeWeightedDigraph, s int) *AcyclicLP { 20 | n := g.V() 21 | distTo := make([]graphs.Distance, n) 22 | edgeTo := make([]*digraph.DirectedEdge, n) 23 | 24 | alp := &AcyclicLP{g, s, distTo, edgeTo} 25 | 26 | alp.validateVertex(s) 27 | 28 | for i := 0; i < n; i++ { 29 | distTo[i] = graphs.DistanceNegativeInfinity 30 | } 31 | distTo[s] = graphs.DistanceZero 32 | 33 | // visit vertices in topological order 34 | topo := digraph.NewTopologicalWeighted(g) 35 | if !topo.HasOrder() { 36 | panic("digraph is not acyclic") 37 | } 38 | for _, v := range topo.Order() { 39 | for _, edge := range g.Adj(v) { 40 | e := edge.(*digraph.DirectedEdge) 41 | alp.relax(e) 42 | } 43 | } 44 | 45 | return alp 46 | } 47 | 48 | // relax edge e, update if find a longer path 49 | func (alp *AcyclicLP) relax(e *digraph.DirectedEdge) { 50 | v, w := e.From(), e.To() 51 | distance := graphs.Distance(e.Weight()) 52 | if alp.distTo[w] < alp.distTo[v]+distance { 53 | alp.distTo[w] = alp.distTo[v] + distance 54 | alp.edgeTo[w] = e 55 | } 56 | } 57 | 58 | // Returns the length of a longest path from the source vertex s to vertex v 59 | func (alp AcyclicLP) DistTo(v int) float64 { 60 | alp.validateVertex(v) 61 | return float64(alp.distTo[v]) 62 | } 63 | 64 | // HasPathTo return true if there is a path from the source vertex to vertx v 65 | func (alp AcyclicLP) HasPathTo(v int) bool { 66 | alp.validateVertex(v) 67 | return alp.distTo[v] > graphs.DistanceNegativeInfinity 68 | } 69 | 70 | // Returns a longest path from the source vertex to vertex v 71 | func (alp *AcyclicLP) PathTo(v int) fund.Iterator { 72 | alp.validateVertex(v) 73 | stack := fund.NewStack() 74 | 75 | if alp.HasPathTo(v) { 76 | for e := alp.edgeTo[v]; e != nil; e = alp.edgeTo[e.From()] { 77 | stack.Push(e) 78 | } 79 | } 80 | 81 | return stack.Iterator() 82 | } 83 | 84 | func (t *AcyclicLP) validateVertex(v int) { 85 | if v < 0 || v >= len(t.distTo) { 86 | panic("invalidate vertex") 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /strings/regexp/nfa.go: -------------------------------------------------------------------------------- 1 | package regexp 2 | 3 | import ( 4 | "github.com/youngzhu/algs4-go/fund" 5 | "github.com/youngzhu/algs4-go/graphs/digraph" 6 | ) 7 | 8 | type NFA struct { 9 | graph digraph.Digraph // digraph of epsilon transition 10 | regExp string // regular expression 11 | m int // number of characters in regular expression 12 | } 13 | 14 | func NewNFA(regExp string) *NFA { 15 | m := len(regExp) 16 | ops := fund.NewStack() 17 | graph := digraph.NewDigraphN(m+1) 18 | for i := 0; i < m; i++ { 19 | lp := i 20 | if regExp[i] == '(' || regExp[i] == '|' { 21 | ops.Push(i) 22 | } else if regExp[i] == ')' { 23 | or := ops.Pop().(int) 24 | 25 | // 2-way or operator 26 | if regExp[or] == '|' { 27 | lp = ops.Pop().(int) 28 | graph.AddEdge(lp, or+1) 29 | graph.AddEdge(or, i) 30 | } else { 31 | lp = or 32 | } 33 | } 34 | 35 | // closure operator (uses 1-character lookahead) 36 | if i < m-1 && regExp[i+1] == '*' { 37 | graph.AddEdge(lp, i+1) 38 | graph.AddEdge(i+1, lp) 39 | } 40 | if regExp[i] == '(' || regExp[i] == '*' || regExp[i] == ')' { 41 | graph.AddEdge(i, i+1) 42 | } 43 | } 44 | 45 | if ops.Size() != 0 { 46 | panic("invalid regular expression") 47 | } 48 | 49 | return &NFA{*graph, regExp, m} 50 | } 51 | 52 | // Returns true if the text is matched by the regular expression 53 | func (p *NFA) Recognizes(txt string) bool { 54 | dfs := digraph.NewDirectedDFS(p.graph, 0) 55 | pc := fund.NewBag() 56 | for v := 0; v < p.graph.V(); v++ { 57 | if dfs.Marked(v) { 58 | pc.Add(v) 59 | } 60 | } 61 | 62 | // Compute possible NFA states for txt[i+1] 63 | for i := 0; i < len(txt); i++ { 64 | cur := txt[i] 65 | if cur == '*' || cur == '|' || cur == '(' || cur == ')' { 66 | panic("the text contains the metacharacter") 67 | } 68 | 69 | match := fund.NewBag() 70 | for _, val := range pc.Iterator() { 71 | v := val.(int) 72 | if v == p.m { 73 | continue 74 | } 75 | if p.regExp[v] == cur || p.regExp[v] == '.' { 76 | match.Add(v+1) 77 | } 78 | } 79 | sources := make([]int, match.Size()) 80 | for i, v := range match.Iterator() { 81 | sources[i] = v.(int) 82 | } 83 | dfs = digraph.NewDirectedDFSN(p.graph, sources) 84 | pc = fund.NewBag() 85 | for v := 0; v < p.graph.V(); v++ { 86 | if dfs.Marked(v) { 87 | pc.Add(v) 88 | } 89 | } 90 | 91 | // optimization if no states reachable 92 | if pc.Size() == 0 { 93 | return false 94 | } 95 | } 96 | 97 | // check for accept state 98 | for _, v := range pc.Iterator() { 99 | if v == p.m { 100 | return true 101 | } 102 | } 103 | return false 104 | } -------------------------------------------------------------------------------- /fund/uf/example_test.go: -------------------------------------------------------------------------------- 1 | package uf_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/youngzhu/algs4-go/fund/uf" 7 | "github.com/youngzhu/algs4-go/testutil" 8 | ) 9 | 10 | func ExampleUF() { 11 | 12 | in := testutil.NewInReadWords("testdata/tinyUF.txt") 13 | 14 | n := in.ReadInt() 15 | unionFind := uf.NewUF(n) 16 | 17 | for !in.IsEmpty() { 18 | p := in.ReadInt() 19 | q := in.ReadInt() 20 | 21 | if unionFind.Find(p) == unionFind.Find(q) { 22 | continue 23 | } 24 | 25 | unionFind.Union(p, q) 26 | fmt.Printf("%d %d\n", p, q) 27 | } 28 | 29 | fmt.Printf("%d components", unionFind.Count()) 30 | 31 | // Output: 32 | // 4 3 33 | // 3 8 34 | // 6 5 35 | // 9 4 36 | // 2 1 37 | // 5 0 38 | // 7 2 39 | // 6 1 40 | // 2 components 41 | } 42 | 43 | func ExampleQuickFindUF() { 44 | 45 | in := testutil.NewInReadWords("testdata/tinyUF.txt") 46 | 47 | n := in.ReadInt() 48 | unionFind := uf.NewQuickFind(n) 49 | 50 | for !in.IsEmpty() { 51 | p := in.ReadInt() 52 | q := in.ReadInt() 53 | 54 | if unionFind.Find(p) == unionFind.Find(q) { 55 | continue 56 | } 57 | 58 | unionFind.Union(p, q) 59 | fmt.Printf("%d %d\n", p, q) 60 | } 61 | 62 | fmt.Printf("%d components", unionFind.Count()) 63 | 64 | // Output: 65 | // 4 3 66 | // 3 8 67 | // 6 5 68 | // 9 4 69 | // 2 1 70 | // 5 0 71 | // 7 2 72 | // 6 1 73 | // 2 components 74 | } 75 | 76 | func ExampleQuickUnionUF() { 77 | 78 | in := testutil.NewInReadWords("testdata/tinyUF.txt") 79 | 80 | n := in.ReadInt() 81 | unionFind := uf.NewQuickUnion(n) 82 | 83 | for !in.IsEmpty() { 84 | p := in.ReadInt() 85 | q := in.ReadInt() 86 | 87 | if unionFind.Find(p) == unionFind.Find(q) { 88 | continue 89 | } 90 | 91 | unionFind.Union(p, q) 92 | fmt.Printf("%d %d\n", p, q) 93 | } 94 | 95 | fmt.Printf("%d components", unionFind.Count()) 96 | 97 | // Output: 98 | // 4 3 99 | // 3 8 100 | // 6 5 101 | // 9 4 102 | // 2 1 103 | // 5 0 104 | // 7 2 105 | // 6 1 106 | // 2 components 107 | } 108 | 109 | func ExampleWeightedQuickUnionUF() { 110 | 111 | in := testutil.NewInReadWords("testdata/tinyUF.txt") 112 | 113 | n := in.ReadInt() 114 | unionFind := uf.NewWeightedQuickUnion(n) 115 | 116 | for !in.IsEmpty() { 117 | p := in.ReadInt() 118 | q := in.ReadInt() 119 | 120 | if unionFind.Find(p) == unionFind.Find(q) { 121 | continue 122 | } 123 | 124 | unionFind.Union(p, q) 125 | fmt.Printf("%d %d\n", p, q) 126 | } 127 | 128 | fmt.Printf("%d components", unionFind.Count()) 129 | 130 | // Output: 131 | // 4 3 132 | // 3 8 133 | // 6 5 134 | // 9 4 135 | // 2 1 136 | // 5 0 137 | // 7 2 138 | // 6 1 139 | // 2 components 140 | } 141 | -------------------------------------------------------------------------------- /graphs/mst/lazy_prim_mst.go: -------------------------------------------------------------------------------- 1 | package mst 2 | 3 | import ( 4 | "github.com/youngzhu/algs4-go/fund" 5 | "github.com/youngzhu/algs4-go/sorting/pq" 6 | ) 7 | 8 | // Lazy implementation. We use priority queue to hold the crossing edges and find 9 | // one of minimal weight. Each time that we add an edge to the tree, we also add 10 | // a vertex to the tree. To maintain the set of crossing edges, we need to add 11 | // to the priority queue all edges from that vertex to any non-tree vertex. But 12 | // we must to do more: andy edge connecting the vertex just added to a tree vertex 13 | // that is already on the priority queue now becomes ineligible (it is no longer 14 | // a crossing edge because it connects two tree vertices). The lazy implementation 15 | // leaves such edges on the priority queue, deferring the ineligibility test to 16 | // when we remove them. 17 | 18 | // It relies on MinPQ 19 | type LazyPrimMST struct { 20 | graph EdgeWeightedGraph 21 | 22 | weight float64 // total weight of MST 23 | mst *fund.Queue // edges in the MST 24 | marked []bool // marked[v]: true if v on tree 25 | epq *pq.MinPQ // edges with one endpoint in tree 26 | } 27 | 28 | func NewLazyPrimMST(g EdgeWeightedGraph) *LazyPrimMST { 29 | mst := fund.NewQueue() 30 | epq := pq.NewMinPQ() 31 | marked := make([]bool, g.V()) 32 | 33 | lp := &LazyPrimMST{graph: g, mst: mst, marked: marked, epq: epq} 34 | 35 | // run Prim from all vertices to get a minimum spanning forest 36 | for v := 0; v < g.V(); v++ { 37 | if !lp.marked[v] { 38 | lp.prim(v) 39 | } 40 | } 41 | 42 | return lp 43 | } 44 | 45 | // run Prim's algorithm 46 | func (lp *LazyPrimMST) prim(s int) { 47 | lp.scan(s) 48 | 49 | // better to stop when mst has V-1 edges smallest edge on pq 50 | for !lp.epq.IsEmpty() { 51 | e := lp.epq.Delete().(*Edge) 52 | // two endpoints 53 | v := e.Either() 54 | w := e.Other(v) 55 | 56 | // lazy, both v and w already scanned 57 | if lp.marked[v] && lp.marked[w] { 58 | continue 59 | } 60 | 61 | lp.mst.Enqueue(e) // add to MST 62 | lp.weight += e.weight 63 | 64 | // v becomes part of tree 65 | if !lp.marked[v] { 66 | lp.scan(v) 67 | } 68 | // w becomes part of tree 69 | if !lp.marked[w] { 70 | lp.scan(w) 71 | } 72 | } 73 | } 74 | 75 | // add all edges e incident to v onto pq 76 | // if the other endpoint has not yet been scanned 77 | func (lp *LazyPrimMST) scan(v int) { 78 | lp.marked[v] = true 79 | for _, edge := range lp.graph.Adj(v) { 80 | e := edge.(*Edge) 81 | if !lp.marked[e.Other(v)] { 82 | lp.epq.Insert(e) 83 | } 84 | } 85 | } 86 | 87 | // Returns the edges in a MST 88 | func (lp *LazyPrimMST) Edges() fund.Iterator { 89 | return lp.mst.Iterator() 90 | } 91 | 92 | // Returns the sum of the edge weights in a MST 93 | func (lp *LazyPrimMST) Weight() float64 { 94 | return lp.weight 95 | } -------------------------------------------------------------------------------- /strings/sort/lsd.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | import "github.com/youngzhu/algs4-go/strings" 4 | 5 | // Least-Significant-Digit First (LSD) radix sort for fixed length strings. 6 | // It includes a method for sorting 32-bit integers, treating each integer as 7 | // a 4-byte string. When N is large, this algorithm is 2-3x faster than the system sort. 8 | 9 | // - Sort a string[] array of n extended ASCII strings (R=256), each of length w 10 | // - Sort an int[] array of n 32-bit integers, treating each integer as a sequence 11 | // of w=4 bytes 12 | 13 | // Uses extra space proportional to n+R 14 | 15 | // Rearranges the array of w-character strings in ascending order. 16 | func LSDSort(a []string) { 17 | // check that strings have fixed length 18 | w := len(a[0]) 19 | for _, s := range a { 20 | if len(s) != w { 21 | panic("strings must have fixed length") 22 | } 23 | } 24 | 25 | n := len(a) 26 | 27 | aux := make([]string, n) 28 | 29 | // sort by key-indexed counting on dth character 30 | for d := w - 1; d >= 0; d-- { 31 | //compute frequency counts 32 | count := make([]int, strings.R+1) 33 | for i := 0; i < n; i++ { 34 | count[a[i][d]+1]++ 35 | } 36 | 37 | // compute cumulates 38 | for r := 0; r < strings.R; r++ { 39 | count[r+1] += count[r] 40 | } 41 | 42 | // move data 43 | for i := 0; i < n; i++ { 44 | aux[count[a[i][d]]] = a[i] 45 | count[a[i][d]]++ 46 | } 47 | 48 | // copy back 49 | for i := 0; i < n; i++ { 50 | a[i] = aux[i] 51 | } 52 | } 53 | } 54 | 55 | /* Didn't work. Don't know why */ 56 | 57 | // Rearranges the array of 32-bit integers in ascending order 58 | func LSDSortInts(a []int) { 59 | bits := 32 // each int is 32 bits 60 | bitsPerByte := 8 61 | R := 1 << bitsPerByte // each bytes is between 0 and 255 62 | mask := R - 1 // 0xFF 63 | w := bits / bitsPerByte // each int is 4 byte 64 | 65 | n := len(a) 66 | aux := make([]int, n) 67 | 68 | for d := 0; d < w; d++ { 69 | // compute frequency counts 70 | count := make([]int, R+1) 71 | for i := 0; i < n; i++ { 72 | c := (a[i] >> bitsPerByte * d) & mask 73 | count[c+1]++ 74 | } 75 | 76 | // compute cumulates 77 | for r := 0; r < R; r++ { 78 | count[r+1] += count[r] 79 | } 80 | 81 | // for most significant byte, 0x80-0xFF come before 0x00-0x7F 82 | if d == w-1 { 83 | shift1 := count[R] - count[R/2] 84 | shift2 := count[R/2] 85 | for r := 0; r < R/2; r++ { 86 | count[r] += shift1 87 | } 88 | for r := R / 2; r < R; r++ { 89 | count[r] -= shift2 90 | } 91 | } 92 | 93 | // move data 94 | for i := 0; i < n; i++ { 95 | c := (a[i] >> bitsPerByte * d) & mask 96 | aux[count[c]] = a[i] 97 | count[c]++ 98 | } 99 | 100 | // copy back 101 | for i := 0; i < n; i++ { 102 | a[i] = aux[i] 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /sorting/heap.go: -------------------------------------------------------------------------------- 1 | package sorting 2 | 3 | // Heapsort. 4 | // We can use any priority queue to develop a sorting method. We insert all 5 | // the keys to be sorted into a minimum-oriented priority queue, then repeatedly 6 | // use remove the minimum to remove them all in order. When using a heap for 7 | // the priority queue, we obtain heapsort. 8 | 9 | // Focusing on the task of sorting, we abandon the notion of hiding the heap 10 | // representation of the priority queue and use swim() and sink() directly. 11 | // Doing so allows us to sort an array without needing any extra space, by 12 | // maintaining the heap within the array to be sorted. Heapsort breaks into two 13 | // phases: heap construction, where we recognize the original array into a 14 | // heap, and the sort-down, where we pull the items out of the heap in 15 | // decreasing order to build the sorted result. 16 | // 17 | // Heap construction. We can accomplish this task in time proportional to NlgN, 18 | // by proceeding from left to right through the array, using swim() to ensure 19 | // that the entries to the left of the scanning pointer make up a heap-ordered 20 | // complete tree, like successive priority queue insertions. A clever method that 21 | // is much more efficient is to proceed from right to left, using sink() to make 22 | // sub-heaps as we go. Every position in the array is the root of a small sub-heap; 23 | // sink() works on such sub-heaps, as well. If the two children of a node are 24 | // heaps, then calling sink() on that node makes the subtree rooted there a heap. 25 | // 26 | // Sort-down. Most of the work during heapsort is done during the second phase, 27 | // where we remove the largest remaining items from the heap and put it into the 28 | // array position vacated as the heap shrinks. 29 | 30 | // Heapsort sink-based heapsort 31 | func Heapsort(x Sortable) { 32 | n := x.Len() 33 | 34 | // heapify phase 35 | for k := n / 2; k >= 1; k-- { 36 | sink(x, k, n) 37 | } 38 | 39 | // sort-down phase 40 | i := n 41 | for i > 1 { 42 | swap(x, 1, i) 43 | i-- 44 | sink(x, 1, i) 45 | } 46 | } 47 | 48 | func sink(x Sortable, k, n int) { 49 | for 2*k <= n { 50 | j := 2 * k 51 | if j < n && less(x, j, j+1) { 52 | j++ 53 | } 54 | if !less(x, k, j) { 55 | break 56 | } 57 | swap(x, k, j) 58 | k = j 59 | } 60 | } 61 | 62 | // Helper functions for comparisons and swaps. 63 | // Indices are "off-by-one" to support 1-based indexing. 64 | func less(x Sortable, i, j int) bool { 65 | return x.Less(i-1, j-1) 66 | } 67 | func swap(x Sortable, i, j int) { 68 | x.Swap(i-1, j-1) 69 | } 70 | 71 | type Heapsorter struct{} 72 | 73 | func NewHeap() Sorter { 74 | return Heapsorter{} 75 | } 76 | 77 | // Implements Sorter 78 | 79 | func (s Heapsorter) SortInts(x []int) { 80 | Heapsort(IntSortSlice(x)) 81 | } 82 | func (s Heapsorter) SortFloat64s(x []float64) { 83 | Heapsort(Float64SortSlice(x)) 84 | } 85 | func (s Heapsorter) SortStrings(x []string) { 86 | Heapsort(StringSortSlice(x)) 87 | } 88 | -------------------------------------------------------------------------------- /sorting/sorting.go: -------------------------------------------------------------------------------- 1 | package sorting 2 | 3 | // See Go src sort.Interface 4 | // An implementation of Sortable can be sorted by the routines in this package. 5 | // The methods refer to elements of the underlying collection by integer index. 6 | 7 | type Sortable interface { 8 | // Len returns the number of elements in the collection 9 | Len() int 10 | 11 | // Less reports whether the element with index i 12 | // must sort before the element with index j 13 | Less(i, j int) bool 14 | 15 | // Swap the elements with indexes i and j 16 | Swap(i, j int) 17 | } 18 | 19 | type Sorter interface { 20 | SortInts(x []int) 21 | SortFloat64s(x []float64) 22 | SortStrings(x []string) 23 | } 24 | 25 | // IsSorted reports whether data is sorted 26 | func IsSorted(data Sortable) bool { 27 | n := data.Len() 28 | for i := n - 1; i > 0; i-- { 29 | if data.Less(i, i-1) { 30 | return false 31 | } 32 | } 33 | return true 34 | } 35 | func IsSortedInts(data []int) bool { 36 | return IsSorted(IntSortSlice(data[0:])) 37 | } 38 | 39 | // Convenience types for common cases 40 | 41 | type ( 42 | // IntSortSlice attaches the methods of Sortable to []int 43 | // sorting in increasing order 44 | IntSortSlice []int 45 | 46 | // Float64SortSlice implements Sortable for a []float64 47 | // sorting in increasing order 48 | // with not-a-number (NaN) values ordered before other values 49 | Float64SortSlice []float64 50 | 51 | // StringSortSlice attaches the methods of Sortable to []string 52 | // sorting in increasing order 53 | StringSortSlice []string 54 | ) 55 | 56 | // IntSortSlice implements 57 | 58 | func (x IntSortSlice) Len() int { 59 | return len(x) 60 | } 61 | func (x IntSortSlice) Less(i, j int) bool { 62 | return x[i] < x[j] 63 | } 64 | func (x IntSortSlice) Swap(i, j int) { 65 | if i == j { 66 | return 67 | } 68 | x[i], x[j] = x[j], x[i] 69 | } 70 | 71 | // Float64SortSlice implements 72 | 73 | func (x Float64SortSlice) Len() int { 74 | return len(x) 75 | } 76 | 77 | // Note that floating-point comparison by itself is not a transitive relation: 78 | // it does not report a consistent ordering for not-a-number (NaN) values. 79 | // This implementation places NaN values before others, by using: 80 | // 81 | // x[i] < x[j] || (math.IsNaN(x[i]) && !math.IsNaN(x[j])) 82 | // 83 | 84 | func (x Float64SortSlice) Less(i, j int) bool { 85 | return x[i] < x[j] || (isNaN(x[i]) && !isNaN(x[j])) 86 | } 87 | func (x Float64SortSlice) Swap(i, j int) { 88 | x[i], x[j] = x[j], x[i] 89 | } 90 | 91 | // A copy of math.IsNaN to avoid a dependency on the math package 92 | func isNaN(f float64) bool { 93 | return f != f 94 | } 95 | 96 | // StringSortSlice implements 97 | 98 | func (x StringSortSlice) Len() int { 99 | return len(x) 100 | } 101 | func (x StringSortSlice) Less(i, j int) bool { 102 | return x[i] < x[j] 103 | } 104 | func (x StringSortSlice) Swap(i, j int) { 105 | x[i], x[j] = x[j], x[i] 106 | } 107 | -------------------------------------------------------------------------------- /sorting/pq/binary_heap.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | // Heap definitions 4 | // The binary heap is a data structure that can efficiently support the basic 5 | // priority-queue operations. In a binary heap, the items are sorted in an array 6 | // such that each key is guaranteed to be larger than (or equal to) the keys at 7 | // two other specific positions. In turn, each of those keys must be larger than 8 | // two more keys, and so forth. This ordering is easy to see if we view the keys 9 | // as being in a binary tree structure with edges from each key to the two keys 10 | // known to be smaller. 11 | 12 | // Definition: A binary tree is heap-ordered if the key in each node is larger 13 | // than (or equal to) the keys in that nodes two children (if any). 14 | 15 | // Proposition 16 | // The largest key in a heap-ordered binary tree is found at the root. 17 | 18 | // Definition 19 | // A binary heap is a set of nodes with keys arranged in a complete heap-ordered 20 | // binary tree, represented in level order in an array (not using the first position). 21 | 22 | // Algorithms on heaps. 23 | // We represent a heap of size n in private array arr[] of length n+1, with arr[0] 24 | // unused and the heap in arr[1] through arr[n]. We access keys only through private 25 | // helper functions Less() and Swap(). The heap operations that we consider work by 26 | // first making a simple modification that could violate the heap condition, then 27 | // traveling through the heap, modifying the heap as required to ensure that the 28 | // heap condition is satisfied everywhere. We refer to this process as heapify. 29 | 30 | // Bottom-up heapify (swim). 31 | // If the heap order is violated because a node's key becomes larger than that 32 | // node's parent key, then we can make progress toward fixing the violation by 33 | // exchanging the node with its parent. After the exchange, the node is larger 34 | // than both its children (one is the old parent, and the other is smaller than 35 | // the old parent because it was a child of that node) but the node may still be 36 | // larger than its parent. We can fix that violation in the same way, and so forth, 37 | // moving up the heap until we reach a node with a larger key, or the root. 38 | 39 | // Top-down heapify (sink). 40 | // If the heap order is violated because a node's key becomes smaller than one 41 | // or both of that node's children's keys, then we can make progress toward fixing 42 | // the violation by exchanging the node with the larger of its two children. This 43 | // switch may cause a violation at the child. We fix that violation in the same 44 | // way, and so forth, moving down the heap until we reach a node with both child 45 | // smaller, or bottom. 46 | 47 | type BinaryHeap interface { 48 | GetLeftChildIndex(p, n int) int 49 | GetRightChildIndex(p, n int) int 50 | GetParentIndex(c, n int) int 51 | GetRootIndex() int 52 | GetLastLeafIndex(n int) int 53 | } 54 | 55 | // default 1-based indexing 56 | func NewBinaryHeap() BinaryHeap { 57 | return BinaryHeapBased1{} 58 | } 59 | 60 | func swap(a []Item, i, j int) { 61 | a[i], a[j] = a[j], a[i] 62 | } 63 | -------------------------------------------------------------------------------- /graphs/mst/edge_weighted_graph.go: -------------------------------------------------------------------------------- 1 | package mst 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/youngzhu/algs4-go/fund" 7 | "github.com/youngzhu/algs4-go/testutil" 8 | ) 9 | 10 | type EdgeWeightedGraph struct { 11 | vertices int // number of vertices 12 | edges int // number of edges 13 | adj []*fund.Bag 14 | } 15 | 16 | func NewEdgeWeightedGraphIn(in *testutil.In) *EdgeWeightedGraph { 17 | if in == nil { 18 | panic("argument is nil") 19 | } 20 | 21 | vertices := in.ReadInt() 22 | if vertices < 0 { 23 | panic("Number of vertices must be non-negative") 24 | } 25 | adj := make([]*fund.Bag, vertices) 26 | for v := 0; v < vertices; v++ { 27 | adj[v] = fund.NewBag() 28 | } 29 | 30 | edges := in.ReadInt() 31 | if edges < 0 { 32 | panic("Number of edges must be non-negative") 33 | } 34 | 35 | // AddEdge() will update g.edges 36 | g := &EdgeWeightedGraph{vertices, 0, adj} 37 | 38 | var v, w int 39 | for i := 0; i < edges; i++ { 40 | v, w = in.ReadInt(), in.ReadInt() 41 | g.validateVertex(v) 42 | g.validateVertex(w) 43 | weight := in.ReadFloat() 44 | e := NewEdge(v, w, weight) 45 | g.AddEdge(e) 46 | } 47 | 48 | return g 49 | } 50 | 51 | // Returns the number of vertices in this edge-weighted graph 52 | func (g *EdgeWeightedGraph) V() int { 53 | return g.vertices 54 | } 55 | 56 | // Returns the number of edges in this edge-weighted graph 57 | func (g *EdgeWeightedGraph) E() int { 58 | return g.edges 59 | } 60 | 61 | // Add the undirected edge to this edge-weighted graph 62 | func (g *EdgeWeightedGraph) AddEdge(e *Edge) { 63 | v := e.Either() 64 | w := e.Other(v) 65 | g.validateVertex(v) 66 | g.validateVertex(w) 67 | g.adj[v].Add(e) 68 | g.adj[w].Add(e) 69 | g.edges++ 70 | } 71 | 72 | // Returns the edges incident on vertex v 73 | func (g *EdgeWeightedGraph) Adj(v int) fund.Iterator { 74 | g.validateVertex(v) 75 | return g.adj[v].Iterator() 76 | } 77 | 78 | // Returns the degree of vertex v 79 | func (g *EdgeWeightedGraph) Degree(v int) int { 80 | g.validateVertex(v) 81 | return g.adj[v].Size() 82 | } 83 | 84 | // Returns all edges in this edge-weighted graph 85 | func (g *EdgeWeightedGraph) Edges() fund.Iterator { 86 | bag := fund.NewBag() 87 | for v := 0; v < g.V(); v++ { 88 | selfLoops := 0 89 | for _, edge := range g.Adj(v) { 90 | e := edge.(*Edge) 91 | if e.Other(v) > v { 92 | bag.Add(e) 93 | } else if e.Other(v) == v { 94 | // add only one copy of each slef loop (self loops will be consecutive) 95 | if selfLoops%2 == 0 { 96 | bag.Add(e) 97 | } 98 | selfLoops++ 99 | } 100 | } 101 | 102 | } 103 | return bag.Iterator() 104 | } 105 | 106 | // Returns a string representation of this edge-weighted graph 107 | func (g *EdgeWeightedGraph) String() string { 108 | s := fmt.Sprintf("vertices:%d, edges:%d\n", g.V(), g.E()) 109 | for v := 0; v < g.V(); v++ { 110 | s += fmt.Sprintf("%d:", v) 111 | for _, e := range g.Adj(v) { 112 | s += fmt.Sprintf(" %v", e) 113 | } 114 | s += fmt.Sprintln() 115 | } 116 | 117 | return s 118 | } 119 | 120 | func (g *EdgeWeightedGraph) validateVertex(v int) { 121 | if v < 0 || v >= g.V() { 122 | panic("invalidate vertex") 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /sorting/pq/max_pq.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | type MaxPQ struct { 4 | items []Item 5 | n int 6 | BinaryHeap 7 | } 8 | 9 | // factory method 10 | // one-based heap has slightly better performance 11 | // see bench_test.go 12 | 13 | func NewMaxPQN(n int) *MaxPQ { 14 | items := make([]Item, n+1) 15 | heap := NewBinaryHeapBased1() 16 | return &MaxPQ{items, 0, heap} 17 | } 18 | func NewMaxPQ() *MaxPQ { 19 | items := make([]Item, 1) 20 | heap := NewBinaryHeapBased1() 21 | return &MaxPQ{items, 0, heap} 22 | } 23 | 24 | // Implement interface PriorityQueue 25 | 26 | func (pq *MaxPQ) Insert(item Item) { 27 | // double size of array if necessary 28 | if pq.n == len(pq.items)-1 { 29 | pq.resize(2 * len(pq.items)) 30 | } 31 | 32 | // add item, and percolate it up to maintain heap invariant 33 | pq.n++ 34 | 35 | lastLeaf := pq.GetLastLeafIndex(pq.n) 36 | pq.items[lastLeaf] = item 37 | pq.swim(lastLeaf, lastLeaf) 38 | } 39 | 40 | func (pq *MaxPQ) swim(child, max int) { 41 | parent := pq.GetParentIndex(child, max) 42 | 43 | if parent != -1 && pq.isHigherPriority(child, parent) { 44 | swap(pq.items, parent, child) 45 | pq.swim(parent, max) 46 | } 47 | } 48 | 49 | // if pq.items[i] higher than pq.items[j] 50 | func (pq *MaxPQ) isHigherPriority(i, j int) bool { 51 | i1 := pq.items[i] 52 | i2 := pq.items[j] 53 | return i1.CompareTo(i2) > 0 54 | } 55 | 56 | func (pq *MaxPQ) Delete() Item { 57 | if pq.IsEmpty() { 58 | panic("The priority queue is empty") 59 | } 60 | 61 | rootIdx := pq.GetRootIndex() 62 | lastLeaf := pq.GetLastLeafIndex(pq.n) 63 | 64 | item := pq.items[rootIdx] 65 | 66 | swap(pq.items, rootIdx, lastLeaf) 67 | 68 | pq.sink(rootIdx, lastLeaf-1) 69 | 70 | pq.n-- 71 | 72 | if pq.n > 0 && pq.n == (len(pq.items)-1)/4 { 73 | pq.resize(len(pq.items) / 2) 74 | } 75 | 76 | return item 77 | } 78 | 79 | func (pq *MaxPQ) sink(parent, max int) { 80 | higherPriorityChild := pq.getHighPriorityChild(parent, max) 81 | 82 | // if the left and right child do not exist 83 | // stop sinking 84 | if higherPriorityChild == -1 { 85 | return 86 | } 87 | 88 | if pq.isHigherPriority(higherPriorityChild, parent) { 89 | swap(pq.items, higherPriorityChild, parent) 90 | pq.sink(higherPriorityChild, max) 91 | } 92 | } 93 | 94 | func (pq *MaxPQ) getHighPriorityChild(parent, max int) int { 95 | leftChild := pq.GetLeftChildIndex(parent, max) 96 | rightChild := pq.GetRightChildIndex(parent, max) 97 | 98 | if leftChild != -1 && rightChild != -1 { 99 | if pq.isHigherPriority(leftChild, rightChild) { 100 | return leftChild 101 | } else { 102 | return rightChild 103 | } 104 | } else if leftChild != -1 { 105 | return leftChild 106 | } else if rightChild != -1 { 107 | return rightChild 108 | } else { 109 | return -1 110 | } 111 | 112 | } 113 | 114 | func (pq *MaxPQ) IsEmpty() bool { 115 | return pq.n == 0 116 | } 117 | 118 | func (pq *MaxPQ) Size() int { 119 | return pq.n 120 | } 121 | 122 | func (pq *MaxPQ) resize(capacity int) { 123 | t := make([]Item, capacity) 124 | copy(t, pq.items) 125 | pq.items = t 126 | } 127 | 128 | func (pq *MaxPQ) GetItems() []Item { 129 | begin := pq.GetRootIndex() 130 | end := pq.GetLastLeafIndex(pq.n) 131 | return pq.items[begin : end+1] 132 | } 133 | -------------------------------------------------------------------------------- /testutil/example_in_test.go: -------------------------------------------------------------------------------- 1 | package testutil_test 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | "github.com/youngzhu/algs4-go/testutil" 8 | ) 9 | 10 | func ExampleIn_ReadString() { 11 | in := testutil.NewInReadWords("testdata/in.txt") 12 | for !in.IsEmpty() { 13 | fmt.Println(in.ReadString()) 14 | } 15 | // Output: 16 | // hello 17 | // Gopher 18 | // wating 19 | // for 20 | // you 21 | } 22 | 23 | func ExampleIn_ReadLine() { 24 | in := testutil.NewIn("testdata/in.txt") 25 | for in.HasNext() { 26 | fmt.Println(in.ReadLine()) 27 | } 28 | // Output: 29 | // hello Gopher 30 | // wating for you 31 | } 32 | 33 | func ExampleIn_ReadString_gz() { 34 | in := testutil.NewInReadWords("testdata/in.txt.gz") 35 | for !in.IsEmpty() { 36 | fmt.Println(in.ReadString()) 37 | } 38 | // Output: 39 | // hello 40 | // Gopher 41 | // wating 42 | // for 43 | // you 44 | } 45 | 46 | func ExampleIn_ReadInt() { 47 | in := testutil.NewInReadWords("testdata/ints.txt") 48 | for !in.IsEmpty() { 49 | fmt.Println(in.ReadInt()) 50 | } 51 | // Output: 52 | // 12 53 | // 3 54 | // -1 55 | // 5 56 | // 6 57 | } 58 | 59 | func ExampleIn_ReadInt_part() { 60 | in := testutil.NewInReadWords("testdata/ints.txt") 61 | 62 | fmt.Println(in.ReadInt()) 63 | fmt.Println(in.ReadInt()) 64 | fmt.Println(in.ReadInt()) 65 | 66 | // Output: 67 | // 12 68 | // 3 69 | // -1 70 | } 71 | 72 | func ExampleIn_ReadFloat() { 73 | in := testutil.NewInReadWords("testdata/floats.txt") 74 | for !in.IsEmpty() { 75 | fmt.Printf("%.6f\n", in.ReadFloat()) 76 | } 77 | 78 | // Output: 79 | // 0.000000 80 | // 0.100000 81 | // 99.990000 82 | // 100.000000 83 | // 0.000009 84 | } 85 | 86 | func ExampleIn_ReadAllStrings() { 87 | in := testutil.NewInReadWords("testdata/in.txt") 88 | s := in.ReadAllStrings() 89 | fmt.Println(s) 90 | // Output: 91 | // [hello Gopher wating for you] 92 | } 93 | 94 | func ExampleIn_ReadAllInts() { 95 | in := testutil.NewInReadWords("testdata/ints.txt") 96 | s := in.ReadAllInts() 97 | fmt.Println(s) 98 | // Output: 99 | // [12 3 -1 5 6] 100 | } 101 | 102 | func ExampleIn_ReadAllStrings_http() { 103 | const url = "https://algs4.cs.princeton.edu/24pq/tiny.txt" 104 | in := testutil.NewInReadWords(url) 105 | s := in.ReadAllStrings() 106 | fmt.Println(s) 107 | // Output: 108 | // [S O R T E X A M P L E] 109 | } 110 | 111 | func ExampleIn_ReadAll_http() { 112 | const url = "https://algs4.cs.princeton.edu/21elementary/words3.txt" 113 | in := testutil.NewIn(url) 114 | s := in.ReadAll() 115 | fmt.Println(s) 116 | 117 | // Output: 118 | 119 | // bed bug dad yes zoo 120 | // now for tip ilk dim 121 | // tag jot sob nob sky 122 | // hut men egg few jay 123 | // owl joy rap gig wee 124 | // was wad fee tap tar 125 | // dug jam all bad yet 126 | } 127 | 128 | func ExampleIn_ReadAllLines() { 129 | in := testutil.NewIn("testdata/in.txt") 130 | lines := in.ReadAllLines() 131 | 132 | for _, line := range lines { 133 | fmt.Println(line) 134 | } 135 | 136 | // Output: 137 | // hello Gopher 138 | // wating for you 139 | } 140 | 141 | func ExampleIn_error() { 142 | _, err := testutil.NewInWithError("") 143 | 144 | fmt.Println(errors.Is(err, testutil.ErrEmpty)) 145 | 146 | // Output: 147 | // true 148 | } 149 | -------------------------------------------------------------------------------- /graphs/sp/dijkstra_sp.go: -------------------------------------------------------------------------------- 1 | package sp 2 | 3 | import ( 4 | "github.com/youngzhu/algs4-go/graphs" 5 | "github.com/youngzhu/algs4-go/graphs/digraph" 6 | "github.com/youngzhu/algs4-go/fund" 7 | "github.com/youngzhu/algs4-go/sorting/pq" 8 | ) 9 | 10 | // Dijkstra's algorithm. 11 | // Dijkstra's algorithm initalizing dist[s] to 0 and all other distTo[] entries 12 | // to positive infinity. Then, it repeatedly relaxes and adds to the tree a 13 | // non-tree vertex with the lowest distTo[] value, counting until all vertices 14 | // are on the tree or non-tree vertex has a finite distTo[] value. 15 | 16 | // Assumes all weights are non-negative. 17 | 18 | type DijkstraSP struct { 19 | graph digraph.EdgeWeightedDigraph 20 | source int 21 | distTo []graphs.Distance // distTo[v]: distance of shortest s->v path 22 | edgeTo []*digraph.DirectedEdge // edgeTo[v]: last edge on shortest s->v path 23 | ipq *pq.MinIndexPQ // priority queue of vertices 24 | } 25 | 26 | func NewDijkstraSP(g digraph.EdgeWeightedDigraph, s int) *DijkstraSP { 27 | for _, edge := range g.Edges() { 28 | e := edge.(*digraph.DirectedEdge) 29 | if e.Weight() < 0 { 30 | panic("negative weight") 31 | } 32 | } 33 | 34 | n := g.V() 35 | distTo := make([]graphs.Distance, n) 36 | edgeTo := make([]*digraph.DirectedEdge, n) 37 | ipq := pq.NewMinIndexPQ(n) 38 | 39 | sp := &DijkstraSP{g, s, distTo, edgeTo, ipq} 40 | 41 | sp.validateVertex(s) 42 | 43 | for i := 0; i < n; i++ { 44 | distTo[i] = graphs.DistanceInfinity 45 | } 46 | distTo[s] = graphs.DistanceZero 47 | 48 | sp.ipq.Insert(s, distTo[s]) 49 | 50 | // relax vertices in order of distance from s 51 | for !sp.ipq.IsEmpty() { 52 | v := sp.ipq.Delete() 53 | for _, edge := range g.Adj(v) { 54 | e := edge.(*digraph.DirectedEdge) 55 | sp.relax(e) 56 | } 57 | } 58 | 59 | return sp 60 | } 61 | 62 | // relax edge e and update pq if changed 63 | func (sp *DijkstraSP) relax(e *digraph.DirectedEdge) { 64 | v, w := e.From(), e.To() 65 | distance := graphs.Distance(e.Weight()) 66 | if sp.distTo[w] > sp.distTo[v] + distance { 67 | sp.distTo[w] = sp.distTo[v] + distance 68 | sp.edgeTo[w] = e 69 | 70 | if sp.ipq.Contains(w) { 71 | sp.ipq.Decrease(w, sp.distTo[w]) 72 | } else { 73 | sp.ipq.Insert(w, sp.distTo[w]) 74 | } 75 | } 76 | } 77 | 78 | // Returns the length of a shortest path from the source vertex s to vertex v 79 | func (sp DijkstraSP) DistTo(v int) float64 { 80 | sp.validateVertex(v) 81 | return float64(sp.distTo[v]) 82 | } 83 | 84 | // Rtrurn true if there is a path from the source vertex to vertx v 85 | func (sp DijkstraSP) HasPathTo(v int) bool { 86 | sp.validateVertex(v) 87 | return sp.distTo[v] < graphs.DistanceInfinity 88 | } 89 | 90 | // Returns a shortest path from the source vertex to vertex v 91 | func (sp DijkstraSP) PathTo(v int) fund.Iterator { 92 | sp.validateVertex(v) 93 | stack := fund.NewStack() 94 | 95 | if sp.HasPathTo(v) { 96 | for e := sp.edgeTo[v]; e != nil; e = sp.edgeTo[e.From()] { 97 | stack.Push(e) 98 | } 99 | } 100 | 101 | return stack.Iterator() 102 | } 103 | 104 | func (sp *DijkstraSP) Source() int { 105 | return sp.source 106 | } 107 | 108 | func (t *DijkstraSP) validateVertex(v int) { 109 | if v < 0 || v >= len(t.distTo) { 110 | panic("invalidate vertex") 111 | } 112 | } -------------------------------------------------------------------------------- /searching/sequential_search.go: -------------------------------------------------------------------------------- 1 | package searching 2 | 3 | // Sequential search in an unordered linked list. 4 | // SequentialSearchST implements a symbol table with a linked list of nodes 5 | // that contains keys and values. To implement get(), we scan through the list, 6 | // using equals() to compare the search key with the key in each node in th list. 7 | // If we find the match, we return the associated value; if not, we return nil. 8 | // To implement put(), we also scan through the list, using equals() to compare 9 | // the client key with the key in each node in the list. If we find the match, 10 | // we update the value associated with that key to be the value given; if not, 11 | // we create a new node with the given key and value, and insert it at the 12 | // beginning of the list. This method is known as sequential search. 13 | 14 | type SequentialSearchST struct { 15 | size int // number of key-value pairs 16 | head *node // the linked list of key-value pairs 17 | } 18 | 19 | // a helper linked list data type 20 | type node struct { 21 | key STKey 22 | value STValue 23 | next *node 24 | } 25 | 26 | func NewSequentialSearchST() *SequentialSearchST { 27 | return &SequentialSearchST{} 28 | } 29 | 30 | // Get returns the value associated with the given key 31 | // in this symbol table 32 | func (st *SequentialSearchST) Get(key STKey) STValue { 33 | if key == nil { 34 | panic("argument to Get() is nil") 35 | } 36 | for x := st.head; x != nil; x = x.next { 37 | if x.key == key { 38 | return x.value 39 | } 40 | } 41 | return nil 42 | } 43 | 44 | // Put inserts the specified key-value pair into the symbol table, 45 | // overwriting the old value with the new value if the symbol 46 | // table already contains the specified key. 47 | // Deletes the specified key (and its associated value) from the 48 | // symbol table if the specified value is nil 49 | func (st *SequentialSearchST) Put(key STKey, value STValue) { 50 | if key == nil { 51 | panic("argument to Put() is nil") 52 | } 53 | if value == nil { 54 | st.Delete(key) 55 | return 56 | } 57 | 58 | for x := st.head; x != nil; x = x.next { 59 | if key == x.key { 60 | x.value = value 61 | return 62 | } 63 | } 64 | 65 | st.head = &node{key, value, st.head} 66 | st.size++ 67 | } 68 | 69 | // Delete remove the specified key and its associated value from the symbol 70 | // table (if the key is in the symbol table) 71 | func (st *SequentialSearchST) Delete(key STKey) { 72 | if key == nil { 73 | panic("argument to Delete() is nil") 74 | } 75 | st.head = st.deleteNode(st.head, key) 76 | } 77 | 78 | // delete key in linked list beginning at node x 79 | // warning: function call stack too large if table is large 80 | func (st *SequentialSearchST) deleteNode(x *node, key STKey) *node { 81 | if x == nil { 82 | return nil 83 | } 84 | if key == x.key { 85 | st.size-- 86 | return x.next 87 | } 88 | x.next = st.deleteNode(x.next, key) 89 | return x 90 | } 91 | 92 | // Keys return all keys in the symbol table 93 | func (st *SequentialSearchST) Keys() []STKey { 94 | var keys []STKey 95 | for x := st.head; x != nil; x = x.next { 96 | keys = append(keys, x.key) 97 | } 98 | return keys 99 | } 100 | 101 | func (st *SequentialSearchST) Contains(key STKey) bool { 102 | return st.Get(key) != nil 103 | } 104 | -------------------------------------------------------------------------------- /sorting/pq/min_pq.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | type MinPQ struct { 4 | items []Item 5 | n int 6 | BinaryHeap 7 | } 8 | 9 | // factory method 10 | func NewMinPQN(n int) *MinPQ { 11 | items := make([]Item, n+1) 12 | heap := NewBinaryHeap() 13 | return &MinPQ{items, 0, heap} 14 | } 15 | func NewMinPQ() *MinPQ { 16 | items := make([]Item, 1) 17 | return &MinPQ{items, 0, NewBinaryHeap()} 18 | } 19 | 20 | // Implement interface PriorityQueue 21 | func (pq *MinPQ) Insert(item Item) { 22 | // double size of array if necessary 23 | if pq.n == len(pq.items)-1 { 24 | pq.resize(2 * len(pq.items)) 25 | } 26 | 27 | // add item, and percolate it up to maintain heap invariant 28 | pq.n++ 29 | 30 | lastLeaf := pq.GetLastLeafIndex(pq.n) 31 | pq.items[lastLeaf] = item 32 | pq.swim(lastLeaf, lastLeaf) 33 | } 34 | 35 | // Loop vs Recursive: almost the same 36 | // see bench_test.go 37 | func (pq *MinPQ) swim(child, max int) { 38 | root := pq.GetRootIndex() 39 | 40 | for child > root { 41 | parent := pq.GetParentIndex(child, max) 42 | if pq.isHigherPriority(parent, child) { 43 | break 44 | } 45 | swap(pq.items, parent, child) 46 | child = parent 47 | } 48 | } 49 | 50 | // if pq.items[i] higher than pq.items[j] 51 | func (pq *MinPQ) isHigherPriority(i, j int) bool { 52 | i1 := pq.items[i] 53 | i2 := pq.items[j] 54 | // different from MaxPQ 55 | return i1.CompareTo(i2) <= 0 56 | } 57 | 58 | func (pq *MinPQ) Delete() Item { 59 | if pq.IsEmpty() { 60 | panic("The priority queue is empty") 61 | } 62 | 63 | rootIdx := pq.GetRootIndex() 64 | lastLeaf := pq.GetLastLeafIndex(pq.n) 65 | 66 | item := pq.items[rootIdx] 67 | 68 | swap(pq.items, rootIdx, lastLeaf) 69 | 70 | pq.sink(rootIdx, lastLeaf-1) 71 | 72 | pq.n-- 73 | 74 | if pq.n > 0 && pq.n == (len(pq.items)-1)/4 { 75 | pq.resize(len(pq.items) / 2) 76 | } 77 | 78 | return item 79 | } 80 | 81 | func (pq *MinPQ) sink(parent, max int) { 82 | for { 83 | higherPriorityChild := pq.getHighPriorityChild(parent, max) 84 | 85 | // if the left and right child do not exist 86 | // stop sinking 87 | if higherPriorityChild == -1 { 88 | break 89 | } 90 | 91 | if pq.isHigherPriority(parent, higherPriorityChild) { 92 | break 93 | } 94 | 95 | swap(pq.items, higherPriorityChild, parent) 96 | parent = higherPriorityChild 97 | } 98 | } 99 | 100 | func (pq *MinPQ) getHighPriorityChild(parent, max int) int { 101 | leftChild := pq.GetLeftChildIndex(parent, max) 102 | rightChild := pq.GetRightChildIndex(parent, max) 103 | 104 | if leftChild != -1 && rightChild != -1 { 105 | if pq.isHigherPriority(leftChild, rightChild) { 106 | return leftChild 107 | } else { 108 | return rightChild 109 | } 110 | } else if leftChild != -1 { 111 | return leftChild 112 | } else if rightChild != -1 { 113 | return rightChild 114 | } else { 115 | return -1 116 | } 117 | 118 | } 119 | 120 | func (pq *MinPQ) IsEmpty() bool { 121 | return pq.n == 0 122 | } 123 | 124 | func (pq *MinPQ) Size() int { 125 | return pq.n 126 | } 127 | 128 | func (pq *MinPQ) resize(capacity int) { 129 | t := make([]Item, capacity) 130 | copy(t, pq.items) 131 | pq.items = t 132 | } 133 | 134 | func (pq *MinPQ) GetItems() []Item { 135 | begin := pq.GetRootIndex() 136 | end := pq.GetLastLeafIndex(pq.n) 137 | return pq.items[begin : end+1] 138 | } 139 | -------------------------------------------------------------------------------- /graphs/graph/symbol_graph.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/youngzhu/algs4-go/searching" 7 | "github.com/youngzhu/algs4-go/testutil" 8 | ) 9 | 10 | // Symbol graphs. 11 | // Typical applications involve processing graphs using strings, not integer 12 | // indices, to difine and refer to vertices. To accommodate such applications, 13 | // we define an input format with the following properties: 14 | // 1. Vertex names are strings. 15 | // 2. A specified delimiter separates vertex names (to allow for the possibility 16 | // of spaces in names). 17 | // 3. Each line represents a set of edges, connecting the first vertex name on 18 | // the line to each of the other vertices named on the line 19 | 20 | // Three data structures: 21 | // 1. A symbol table st with string keys (vertex names) and int values (indices) 22 | // 2. An array keys[] that serves as an inverted index, giving the vertex name 23 | // associated with each integer index 24 | // 3. A graph built using the indices to refer to vertices 25 | type SymbolGraph struct { 26 | st searching.RedBlackBST // string -> index 27 | keys []string // index -> string 28 | graph Graph // the underlying graph 29 | } 30 | 31 | // New a Symbol Graph from a file using the specified delimiter. 32 | // Each line in the file contains the name of a vertex, 33 | // followed by a list of the names of the vertices adjacent to that vertex, 34 | // separated by the delimiter. 35 | func NewSymbolGraph(filepath, delimiter string) SymbolGraph { 36 | st := searching.NewRedBlackBST() 37 | 38 | // first pass builds the index by reading strings to associate 39 | // distinct strings with an index 40 | in := testutil.NewInReadLines(filepath) 41 | for in.HasNext() { 42 | slice := strings.Split(in.ReadLine(), delimiter) 43 | for _, v := range slice { 44 | key := searching.StringKey(v) 45 | if !st.Contains(key) { 46 | st.Put(key, st.Size()) 47 | } 48 | } 49 | } 50 | 51 | // inverted index to get string keys in an array 52 | keys := make([]string, st.Size()) 53 | for _, k := range st.Keys() { 54 | i := st.Get(k).(int) 55 | keys[i] = string(k.(searching.StringKey)) 56 | } 57 | 58 | // second pass builds the graph by connecting first vertex 59 | // on each line to all others 60 | graph := NewGraphN(st.Size()) 61 | in = testutil.NewIn(filepath) 62 | for in.HasNext() { 63 | slice := strings.Split(in.ReadLine(), delimiter) 64 | key := searching.StringKey(slice[0]) 65 | v := st.Get(key).(int) // first vertex 66 | var w int 67 | for _, str := range slice[1:] { 68 | key = searching.StringKey(str) 69 | w = st.Get(key).(int) 70 | graph.AddEdge(v, w) 71 | } 72 | } 73 | 74 | return SymbolGraph{*st, keys, *graph} 75 | } 76 | 77 | // Does the graph contain the vertex named s 78 | func (sg SymbolGraph) Contains(s string) bool { 79 | key := searching.StringKey(s) 80 | return sg.st.Contains(key) 81 | } 82 | 83 | // Returns the integer associated with the vertex named s 84 | func (sg SymbolGraph) Index(s string) int { 85 | key := searching.StringKey(s) 86 | return sg.st.Get(key).(int) 87 | } 88 | 89 | // Returns the name of the vertex associated with the integer v 90 | func (sg SymbolGraph) Name(v int) string { 91 | sg.graph.validateVertex(v) 92 | return sg.keys[v] 93 | } 94 | 95 | // Returns the graph associated with the symbol graph 96 | func (sg SymbolGraph) Graph() Graph { 97 | return sg.graph 98 | } 99 | -------------------------------------------------------------------------------- /graphs/graph/breadth_first_paths.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "github.com/youngzhu/algs4-go/fund" 5 | "github.com/youngzhu/algs4-go/graphs" 6 | ) 7 | 8 | // Breadth-first search. 9 | // Depth-first search finds some path from a source vertex s to a target vertex v. 10 | // We are often interested in finding the shortest such path (one with a minimal 11 | // number of edges). Breadth-first search is a classic method based on this goal. 12 | // To find a shortest path from s to v, we start at s and check for v among all 13 | // the vertices that we can reach by following one edge, then we check for v among 14 | // all the vertices that we can reach from s by following two edges, and so forth. 15 | 16 | // To implement this strategy, we maintain a queue of all vertices that have been 17 | // marked but whose adjacency lists have not been checked. We put the source vertex 18 | // on the queue, then perform the following steps until the queue is empty: 19 | // 1. Remove the next vertex v from the queue 20 | // 2. Put onto the queue all unmarked vertices that are adjacent to v and mark them 21 | 22 | type BreadthFirstPaths struct { 23 | graph Graph 24 | source int // source vertex 25 | marked []bool // marked[v]: is there an s-v path? 26 | edgeTo []int // edgeTo[v]: previous edge on shortest s-v path 27 | distTo []int // distTo[v]: number of edges on shortest s-v path 28 | } 29 | 30 | // Computes the shortest path between the source vertex (s) 31 | // and every other vertex in graph g 32 | func NewBreadthFirstPaths(g Graph, s int) BreadthFirstPaths { 33 | g.validateVertex(s) 34 | 35 | marked := make([]bool, g.V()) 36 | edgeTo := make([]int, g.V()) 37 | distTo := make([]int, g.V()) 38 | 39 | for v := 0; v < g.V(); v++ { 40 | distTo[v] = graphs.InfinityDistance 41 | } 42 | 43 | path := BreadthFirstPaths{g, s, marked, edgeTo, distTo} 44 | path.bfs() 45 | 46 | return path 47 | } 48 | 49 | // breadth first search from s 50 | func (p BreadthFirstPaths) bfs() { 51 | queue := fund.NewQueue() 52 | 53 | p.marked[p.source] = true 54 | p.distTo[p.source] = 0 55 | queue.Enqueue(fund.Item(p.source)) 56 | 57 | for !queue.IsEmpty() { 58 | v := queue.Dequeue().(int) 59 | 60 | for _, ww := range p.graph.Adj(v) { 61 | w := ww.(int) 62 | if !p.marked[w] { 63 | p.marked[w] = true 64 | p.edgeTo[w] = v 65 | p.distTo[w] = p.distTo[v] + 1 66 | queue.Enqueue(fund.Item(w)) 67 | } 68 | } 69 | } 70 | } 71 | 72 | // Is there a path between the source vertex (s) and vertex (v) 73 | func (p BreadthFirstPaths) HasPathTo(v int) bool { 74 | p.graph.validateVertex(v) 75 | return p.marked[v] 76 | } 77 | 78 | // Returns the number of edges in a shortest path between the source vertex s 79 | // and vertex v 80 | func (p BreadthFirstPaths) DistTo(v int) int { 81 | p.graph.validateVertex(v) 82 | return p.distTo[v] 83 | } 84 | 85 | // Returns a path between the source vertex (s) and vertex v 86 | // or nil if no such path 87 | func (p BreadthFirstPaths) PathTo(v int) []int { 88 | if !p.HasPathTo(v) { 89 | return nil 90 | } 91 | 92 | stack := fund.NewStack() 93 | 94 | for x := v; x != p.source; x = p.edgeTo[x] { 95 | stack.Push(fund.Item(x)) 96 | } 97 | stack.Push(fund.Item(p.source)) 98 | 99 | path := make([]int, stack.Size()) 100 | i := 0 101 | for !stack.IsEmpty() { 102 | path[i] = stack.Pop().(int) 103 | i++ 104 | } 105 | 106 | return path 107 | } 108 | -------------------------------------------------------------------------------- /testutil/in.go: -------------------------------------------------------------------------------- 1 | package testutil 2 | 3 | import ( 4 | "bufio" 5 | "compress/gzip" 6 | "errors" 7 | "io" 8 | "net/http" 9 | "os" 10 | "strconv" 11 | "strings" 12 | ) 13 | 14 | // Reads in data of various types from standard input, files and URLs. 15 | 16 | var ErrEmpty = errors.New("argument is empty") 17 | 18 | type In struct { 19 | reader io.Reader 20 | scanner *bufio.Scanner 21 | hasScanned bool 22 | hasNext bool 23 | } 24 | 25 | // Factory method 26 | // default read in lines 27 | func NewInWithError(uri string) (*In, error) { 28 | r, err := newReader(uri) 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | scanner := bufio.NewScanner(r) 34 | 35 | return &In{reader: r, scanner: scanner}, nil 36 | } 37 | 38 | func NewIn(uri string) *In { 39 | return NewInReadLines(uri) 40 | } 41 | 42 | func NewInReadWords(uri string) *In { 43 | r, err := newReader(uri) 44 | if err != nil { 45 | panic(err) 46 | } 47 | 48 | scanner := bufio.NewScanner(r) 49 | 50 | scanner.Split(bufio.ScanWords) 51 | 52 | return &In{reader: r, scanner: scanner} 53 | } 54 | 55 | func NewInReadLines(uri string) *In { 56 | r, err := newReader(uri) 57 | if err != nil { 58 | panic(err) 59 | } 60 | 61 | scanner := bufio.NewScanner(r) 62 | 63 | return &In{reader: r, scanner: scanner} 64 | } 65 | 66 | func newReader(uri string) (io.Reader, error) { 67 | if uri == "" { 68 | return nil, ErrEmpty 69 | } 70 | 71 | // first try to read file from local file system 72 | f, err := os.Open(uri) 73 | if err == nil { 74 | if strings.HasSuffix(uri, ".gz") { 75 | gz, err := gzip.NewReader(f) 76 | if err != nil { 77 | panic(err) 78 | } 79 | return gz, nil 80 | } else { 81 | return f, nil 82 | } 83 | } else { 84 | // URL from web 85 | resp, err := http.Get(uri) 86 | if err != nil { 87 | return nil, err 88 | } 89 | return resp.Body, nil 90 | } 91 | 92 | } 93 | 94 | func (in *In) ReadString() string { 95 | in.next() 96 | return in.scanner.Text() 97 | } 98 | 99 | func (in *In) ReadLine() string { 100 | in.next() 101 | return in.scanner.Text() 102 | } 103 | 104 | func (in *In) ReadInt() int { 105 | i, _ := strconv.Atoi(in.ReadString()) 106 | return i 107 | } 108 | 109 | func (in *In) ReadFloat() float64 { 110 | f, _ := strconv.ParseFloat(in.ReadString(), 64) 111 | return f 112 | } 113 | 114 | func (in *In) IsEmpty() bool { 115 | return !in.HasNext() 116 | } 117 | 118 | func (in *In) HasNext() bool { 119 | if !in.hasScanned { 120 | in.hasNext = in.scanner.Scan() 121 | in.hasScanned = true 122 | } 123 | return in.hasNext 124 | } 125 | 126 | func (in *In) next() bool { 127 | if in.hasScanned { 128 | in.hasScanned = false 129 | return in.hasNext 130 | } 131 | return in.scanner.Scan() 132 | } 133 | 134 | func (in *In) ReadAll() string { 135 | data, err := io.ReadAll(in.reader) 136 | if err != nil { 137 | panic(err) 138 | } 139 | 140 | return string(data) 141 | } 142 | 143 | func (in *In) ReadAllLines() []string { 144 | ss := make([]string, 0) 145 | 146 | for in.HasNext() { 147 | ss = append(ss, in.ReadString()) 148 | } 149 | 150 | return ss 151 | } 152 | 153 | func (in *In) ReadAllStrings() []string { 154 | str := in.ReadAll() 155 | 156 | return strings.Fields(str) 157 | } 158 | 159 | func (in *In) ReadAllInts() []int { 160 | strSlice := in.ReadAllStrings() 161 | n := len(strSlice) 162 | intSlice := make([]int, n) 163 | 164 | for i := 0; i < n; i++ { 165 | intSlice[i], _ = strconv.Atoi(strSlice[i]) 166 | } 167 | 168 | return intSlice 169 | } 170 | -------------------------------------------------------------------------------- /strings/trie/example_test.go: -------------------------------------------------------------------------------- 1 | package trie_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/youngzhu/algs4-go/strings/trie" 7 | "github.com/youngzhu/algs4-go/testutil" 8 | ) 9 | 10 | var trieST *trie.TrieST 11 | 12 | func initTrieST() { 13 | // build ST from file 14 | trieST = trie.NewTrieST() 15 | 16 | in := testutil.NewInReadWords("testdata/shellsST.txt") 17 | a := in.ReadAllStrings() 18 | 19 | for i, s := range a { 20 | trieST.Put(s, i) 21 | } 22 | } 23 | 24 | func ExampleTrieST_Keys() { 25 | if trieST == nil { 26 | initTrieST() 27 | } 28 | 29 | fmt.Println("keys(\"\"):") 30 | for _, v := range trieST.Keys() { 31 | fmt.Printf("%s %d\n", v, trieST.Get(v)) 32 | } 33 | 34 | // Output: 35 | // keys(""): 36 | // by 4 37 | // sea 6 38 | // sells 1 39 | // she 0 40 | // shells 3 41 | // shore 7 42 | // the 5 43 | } 44 | 45 | func ExampleTrieST_LongestPrefixOf() { 46 | if trieST == nil { 47 | initTrieST() 48 | } 49 | 50 | prefix := "shellsort" 51 | fmt.Printf("LongestPrefixOf(\"%s\"):\n", prefix) 52 | fmt.Println(trieST.LongestPrefixOf(prefix)) 53 | fmt.Println() 54 | 55 | prefix = "quicksort" 56 | fmt.Printf("LongestPrefixOf(\"%s\"):\n", prefix) 57 | fmt.Println(trieST.LongestPrefixOf(prefix)) 58 | fmt.Println() 59 | 60 | // Output: 61 | // LongestPrefixOf("shellsort"): 62 | // shells 63 | // 64 | // LongestPrefixOf("quicksort"): 65 | // 66 | // 67 | } 68 | 69 | func ExampleTrieST_KeysWithPrefix() { 70 | if trieST == nil { 71 | initTrieST() 72 | } 73 | 74 | prefix := "shor" 75 | fmt.Printf("KeysWithPrefix(\"%s\"):\n", prefix) 76 | for _, s := range trieST.KeysWithPrefix(prefix) { 77 | fmt.Println(s) 78 | } 79 | 80 | // Output: 81 | // KeysWithPrefix("shor"): 82 | // shore 83 | } 84 | 85 | func ExampleTrieST_KeysThatMatch() { 86 | if trieST == nil { 87 | initTrieST() 88 | } 89 | 90 | pattern := "shor" 91 | fmt.Printf("KeysThatMatch(\"%s\"):\n", pattern) 92 | for _, s := range trieST.KeysThatMatch(pattern) { 93 | fmt.Println(s) 94 | } 95 | fmt.Println() 96 | 97 | pattern = ".he.l." 98 | fmt.Printf("KeysThatMatch(\"%s\"):\n", pattern) 99 | for _, s := range trieST.KeysThatMatch(pattern) { 100 | fmt.Println(s) 101 | } 102 | 103 | // Output: 104 | // KeysThatMatch("shor"): 105 | // 106 | // KeysThatMatch(".he.l."): 107 | // shells 108 | } 109 | 110 | func ExampleTernarySearchTrie() { 111 | tst := trie.NewTernarySearchTrie() 112 | 113 | in := testutil.NewInReadWords("testdata/shellsST.txt") 114 | a := in.ReadAllStrings() 115 | 116 | for i, s := range a { 117 | tst.Put(s, i) 118 | } 119 | 120 | fmt.Println("Keys:") 121 | for _, v := range tst.Keys() { 122 | fmt.Printf("%s %d\n", v, tst.Get(v)) 123 | } 124 | fmt.Println() 125 | 126 | prefix := "shellsort" 127 | fmt.Printf("LongestPrefixOf(\"%s\"):\n", prefix) 128 | fmt.Println(tst.LongestPrefixOf(prefix)) 129 | fmt.Println() 130 | 131 | prefix = "shor" 132 | fmt.Printf("KeysWithPrefix(\"%s\"):\n", prefix) 133 | for _, s := range tst.KeysWithPrefix(prefix) { 134 | fmt.Println(s) 135 | } 136 | fmt.Println() 137 | 138 | pattern := ".he.l." 139 | fmt.Printf("KeysThatMatch(\"%s\"):\n", pattern) 140 | for _, s := range tst.KeysThatMatch(pattern) { 141 | fmt.Println(s) 142 | } 143 | 144 | // Output: 145 | // Keys: 146 | // by 4 147 | // sea 6 148 | // sells 1 149 | // she 0 150 | // shells 3 151 | // shore 7 152 | // the 5 153 | // 154 | // LongestPrefixOf("shellsort"): 155 | // shells 156 | // 157 | // KeysWithPrefix("shor"): 158 | // shore 159 | // 160 | // KeysThatMatch(".he.l."): 161 | // shells 162 | } 163 | -------------------------------------------------------------------------------- /graphs/digraph/digraph.go: -------------------------------------------------------------------------------- 1 | package digraph 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/youngzhu/algs4-go/fund" 7 | "github.com/youngzhu/algs4-go/graphs/graph" 8 | "github.com/youngzhu/algs4-go/testutil" 9 | ) 10 | 11 | // A directed graph (or digraph) is a set of vertices and a collection of directed 12 | // edges that each connects an ordered pair of vertices. We say that a directed 13 | // edge points from the first vertex in the pair and points to the second vertex in 14 | // the pair. We use the names 0 through V-1 for the vertices in a V-vertex graph. 15 | type IDigraph interface { 16 | graph.IGraph 17 | } 18 | 19 | // Use the adjacency-lists representation, where maintain a vertex-indexed array 20 | // of lists of the vertices connected by an edge to each vertex. 21 | type Digraph struct { 22 | v int // number of vertices 23 | e int // number of edges 24 | adj []*fund.Bag // adj[v]: adjacency list for vertex v 25 | indegree []int // indegree[v]: indegree of vertex v 26 | } 27 | 28 | // New an empty digraph with v vertices 29 | func NewDigraphN(v int) *Digraph { 30 | if v < 0 { 31 | panic("number of verties in a Digraph must be non-negative") 32 | } 33 | 34 | adj := make([]*fund.Bag, v) 35 | for i := 0; i < v; i++ { 36 | adj[i] = fund.NewBag() 37 | } 38 | 39 | indegree := make([]int, v) 40 | 41 | return &Digraph{v, 0, adj, indegree} 42 | } 43 | 44 | // New a digraph from the specified input stream. 45 | // The format is the number of vertices V 46 | // followed by the number of edges E 47 | // followed by E pairs of vertices, with each entry separated by whitespace 48 | func NewDigraph(in *testutil.In) *Digraph { 49 | v := in.ReadInt() 50 | 51 | g := NewDigraphN(v) 52 | 53 | e := in.ReadInt() 54 | if e < 0 { 55 | panic("number of edges in a Graph must be non-negative") 56 | } 57 | for i := 0; i < e; i++ { 58 | v1 := in.ReadInt() 59 | v2 := in.ReadInt() 60 | g.AddEdge(v1, v2) 61 | } 62 | 63 | return g 64 | } 65 | 66 | // Returns the number of vertices in this graph 67 | func (g *Digraph) V() int { 68 | return g.v 69 | } 70 | 71 | // Returns the number of edges in this graph 72 | func (g *Digraph) E() int { 73 | return g.e 74 | } 75 | 76 | // Adds the directed edge v1->v2 to this graph 77 | func (g *Digraph) AddEdge(v1, v2 int) { 78 | g.validateVertex(v1) 79 | g.validateVertex(v2) 80 | g.e++ 81 | g.adj[v1].Add(v2) 82 | g.indegree[v2]++ 83 | } 84 | 85 | func (g *Digraph) Outdegree(v int) int { 86 | g.validateVertex(v) 87 | return g.adj[v].Size() 88 | } 89 | 90 | func (g *Digraph) Indegree(v int) int { 91 | g.validateVertex(v) 92 | return g.indegree[v] 93 | } 94 | 95 | func (g *Digraph) Adj(v int) fund.Iterator { 96 | g.validateVertex(v) 97 | return g.adj[v].Iterator() 98 | } 99 | 100 | // Returns the reverse of the digraph 101 | func (g *Digraph) Reverse() *Digraph { 102 | reverse := NewDigraphN(g.V()) 103 | 104 | for v := 0; v < g.V(); v++ { 105 | for _, it := range g.Adj(v) { 106 | w := it.(int) 107 | reverse.AddEdge(w, v) 108 | } 109 | } 110 | 111 | return reverse 112 | } 113 | 114 | // Returns a string representation of this graph 115 | func (g *Digraph) String() string { 116 | s := fmt.Sprintf("%d vertices, %d edges\n", g.v, g.e) 117 | for i := 0; i < g.v; i++ { 118 | adjs := "" 119 | for _, w := range g.adj[i].Iterator() { 120 | adjs += fmt.Sprintf(" %d", w) 121 | } 122 | s += fmt.Sprintf("%d:%s\n", i, adjs) 123 | } 124 | return s 125 | } 126 | 127 | func (g *Digraph) validateVertex(v int) { 128 | if v < 0 || v >= g.v { 129 | panic("invalidate vertex") 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /graphs/mst/eager_prim_mst.go: -------------------------------------------------------------------------------- 1 | package mst 2 | 3 | import ( 4 | "github.com/youngzhu/algs4-go/fund" 5 | "github.com/youngzhu/algs4-go/sorting/pq" 6 | ) 7 | 8 | // Eager implementation. To improve the lazy implementation of Prim's algorithm, 9 | // we might try to delete ineligible edges from the priority queue, so that the 10 | // priority queue contains only the crossing edges. But we can eliminate even 11 | // more edges. The key is to note that our only interest is in the minimal edge 12 | // from each non-tree vertex to a tree vertex. When we add a vertex v to the tree, 13 | // the only possible change with respect to each non-tree vertex w is that adding 14 | // v brings w closer than before to the tree. In short, we do not need to keep on 15 | // the priority queue all of the edges from w to verteices tree—we just need to 16 | // keep track of the minimum-weight edge and check whether the addition of v to the 17 | // tree necessitates that we update that minimum (because of an edge v-w that has 18 | // lower weight), which we can do as we process each edge in s adjacency list. In 19 | // other words, we maintain on the priority queue just on edge for each non-tree 20 | // vertex: the shortest edge that connects it to the tree. 21 | 22 | type distance float64 23 | 24 | func (d distance) CompareTo(x pq.Item) int { 25 | xx := x.(distance) 26 | if d < xx { 27 | return -1 28 | } else if d > xx { 29 | return 1 30 | } else { 31 | return 0 32 | } 33 | } 34 | 35 | type PrimMST struct { 36 | graph EdgeWeightedGraph 37 | edgeTo []*Edge // edgeTo[v]: shortest edge from tree vertex to non-tree vertex 38 | distTo []distance // distTo[v]: weight of shortest such edge 39 | marked []bool // marked[v]: true if v on tree, false otherwise 40 | ipq *pq.MinIndexPQ 41 | } 42 | 43 | const positiveInfinity = 1000000.0 44 | 45 | func NewPrimMST(g EdgeWeightedGraph) *PrimMST { 46 | n := g.V() 47 | edgeTo := make([]*Edge, n) 48 | distTo := make([]distance, n) 49 | marked := make([]bool, n) 50 | ipq := pq.NewMinIndexPQ(n) 51 | 52 | for v := 0; v < n; v++ { 53 | distTo[v] = positiveInfinity 54 | } 55 | 56 | mst := &PrimMST{g, edgeTo, distTo, marked, ipq} 57 | 58 | // run from each vertex to find minimum spanning forest 59 | for v := 0; v < n; v++ { 60 | if !mst.marked[v] { 61 | mst.prim(v) 62 | } 63 | } 64 | 65 | return mst 66 | } 67 | 68 | // run Prim's algorithm starting from vertex s 69 | func (p *PrimMST) prim(s int) { 70 | p.distTo[s] = 0 71 | p.ipq.Insert(s, p.distTo[s]) 72 | for ! p.ipq.IsEmpty() { 73 | v := p.ipq.Delete() 74 | p.scan(v) 75 | } 76 | } 77 | 78 | // scan vertex v 79 | func (p *PrimMST) scan(v int) { 80 | p.marked[v] = true 81 | for _, edge := range p.graph.Adj(v) { 82 | e := edge.(*Edge) 83 | w := e.Other(v) 84 | if p.marked[w] { // v-w is obsolete edge 85 | continue 86 | } 87 | weight := distance(e.Weight()) 88 | if weight < p.distTo[w] { 89 | p.distTo[w] = weight 90 | p.edgeTo[w] = e 91 | if p.ipq.Contains(w) { 92 | p.ipq.Decrease(w, p.distTo[w]) 93 | } else { 94 | p.ipq.Insert(w, p.distTo[w]) 95 | } 96 | } 97 | } 98 | } 99 | 100 | // Returns the edges in a MST 101 | func (p *PrimMST) Edges() fund.Iterator { 102 | mst := fund.NewQueue() 103 | for v := 0; v < len(p.edgeTo); v++ { 104 | e := p.edgeTo[v] 105 | if e != nil { 106 | mst.Enqueue(e) 107 | } 108 | } 109 | return mst.Iterator() 110 | } 111 | 112 | // Returns the sum of the edge weights in a MST 113 | func (p *PrimMST) Weight() float64 { 114 | weight := 0.0 115 | for _, edge := range p.Edges() { 116 | e := edge.(*Edge) 117 | weight += e.Weight() 118 | } 119 | return weight 120 | } -------------------------------------------------------------------------------- /context/suffix/example_test.go: -------------------------------------------------------------------------------- 1 | package suffix_test 2 | 3 | import ( 4 | "fmt" 5 | "github.com/youngzhu/algs4-go/context/suffix" 6 | "github.com/youngzhu/algs4-go/testutil" 7 | "regexp" 8 | ) 9 | 10 | func ExampleSuffixArray() { 11 | in := testutil.NewIn("testdata/abra.txt") 12 | text := in.ReadAll() 13 | 14 | sa := suffix.NewSuffixArray(text) 15 | 16 | testSuffixArray(sa) 17 | 18 | // Output: 19 | //---------------------------- 20 | //i idx lcp rnk ith 21 | //---------------------------- 22 | //0 11 - 0 ! 23 | //1 10 0 1 A! 24 | //2 7 1 2 ABRA! 25 | //3 0 4 3 ABRACADABRA! 26 | //4 3 1 4 ACADABRA! 27 | //5 5 1 5 ADABRA! 28 | //6 8 0 6 BRA! 29 | //7 1 3 7 BRACADABRA! 30 | //8 4 0 8 CADABRA! 31 | //9 6 0 9 DABRA! 32 | //10 9 0 10 RA! 33 | //11 2 2 11 RACADABRA! 34 | } 35 | 36 | func testSuffixArray(sa suffix.SuffixArrayInterface) { 37 | fmt.Println("----------------------------") 38 | fmt.Println("i idx lcp rnk ith") 39 | fmt.Println("----------------------------") 40 | 41 | for i := 0; i < sa.Length(); i++ { 42 | idx := sa.Index(i) 43 | ith := sa.Select(i) 44 | rank := sa.Rank(ith) 45 | if i == 0 { 46 | fmt.Printf("%-3d%-3d %-3s %-3d %s\n", i, idx, "-", rank, ith) 47 | } else { 48 | lcp := sa.LCP(i) 49 | fmt.Printf("%-3d%-3d %-3d %-3d %s\n", i, idx, lcp, rank, ith) 50 | } 51 | } 52 | } 53 | 54 | // Longest Repeated Substring 55 | func ExampleLongestRepeatedSubstring() { 56 | lrs := suffix.LongestRepeatedSubstring("aaaaaaaa") 57 | fmt.Println(lrs) 58 | 59 | lrs = suffix.LongestRepeatedSubstring("abcdefg") 60 | fmt.Println(lrs) 61 | 62 | // Output: 63 | // "aaaaaaa" 64 | // "" 65 | } 66 | 67 | var space = regexp.MustCompile("\\s+") 68 | 69 | func whitespace(s string) string { 70 | // not work 71 | //txt := strings.ReplaceAll(text, "\\s+", " ") 72 | 73 | //space := regexp.MustCompile("\\s+") 74 | t := string(space.ReplaceAll([]byte(s), []byte(" "))) 75 | 76 | return t 77 | } 78 | func ExampleLongestRepeatedSubstring_file() { 79 | in := testutil.NewIn("testdata/tinyTale.txt") 80 | text := in.ReadAll() 81 | s := whitespace(text) 82 | lrs := suffix.LongestRepeatedSubstring(s) 83 | fmt.Println(lrs) 84 | 85 | in = testutil.NewIn("testdata/mobydick.txt.gz") 86 | text = in.ReadAll() 87 | t := whitespace(text) 88 | lrs = suffix.LongestRepeatedSubstring(t) 89 | fmt.Println(lrs) 90 | 91 | // Output: 92 | // "st of times it was the " 93 | // ",- Such a funny, sporty, gamy, jesty, joky, hoky-poky lad, is the Ocean, oh! Th" 94 | } 95 | 96 | func ExampleLongestCommonSubstring() { 97 | in1 := testutil.NewIn("testdata/tale.txt.gz") 98 | text1 := in1.ReadAll() 99 | 100 | in2 := testutil.NewIn("testdata/mobydick.txt.gz") 101 | text2 := in2.ReadAll() 102 | 103 | s, t := whitespace(text1), whitespace(text2) 104 | lcs := suffix.LongestCommonSubstring(s, t) 105 | fmt.Println(lcs) 106 | 107 | // Output: 108 | // " seemed on the point of being " 109 | } 110 | 111 | func ExampleSuffixArrayX() { 112 | in := testutil.NewIn("testdata/abra.txt") 113 | text := in.ReadAll() 114 | 115 | sa := suffix.NewSuffixArrayX(text) 116 | testSuffixArray(sa) 117 | 118 | // Output: 119 | //---------------------------- 120 | //i idx lcp rnk ith 121 | //---------------------------- 122 | //0 11 - 0 ! 123 | //1 10 0 1 A! 124 | //2 7 1 2 ABRA! 125 | //3 0 4 3 ABRACADABRA! 126 | //4 3 1 4 ACADABRA! 127 | //5 5 1 5 ADABRA! 128 | //6 8 0 6 BRA! 129 | //7 1 3 7 BRACADABRA! 130 | //8 4 0 8 CADABRA! 131 | //9 6 0 9 DABRA! 132 | //10 9 0 10 RA! 133 | //11 2 2 11 RACADABRA! 134 | } 135 | -------------------------------------------------------------------------------- /sorting/example_test.go: -------------------------------------------------------------------------------- 1 | package sorting_test 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | 7 | "github.com/youngzhu/algs4-go/sorting" 8 | "github.com/youngzhu/algs4-go/testutil" 9 | ) 10 | 11 | var ( 12 | selectionAlg = sorting.NewSelection() 13 | insertionAlg = sorting.NewInsertion() 14 | shellAlg = sorting.NewShell() 15 | ) 16 | 17 | // ints 18 | func ExampleSelection_ints() { 19 | ints := []int{5, 4, 5, 3, 1, 2} 20 | selectionAlg.SortInts(ints) 21 | fmt.Println(ints) 22 | // Output: 23 | // [1 2 3 4 5 5] 24 | } 25 | func ExampleInsertion_ints() { 26 | ints := []int{5, 4, 5, 3, 1, 2} 27 | insertionAlg.SortInts(ints) 28 | fmt.Println(ints) 29 | // Output: 30 | // [1 2 3 4 5 5] 31 | } 32 | func ExampleShell_ints() { 33 | ints := []int{5, 4, 5, 3, 1, 2} 34 | shellAlg.SortInts(ints) 35 | fmt.Println(ints) 36 | // Output: 37 | // [1 2 3 4 5 5] 38 | } 39 | 40 | // float64s 41 | func ExampleSelection_float64s() { 42 | s := []float64{5.2, -1.3, 0.7, -3.8, 2.6} // unsorted 43 | selectionAlg.SortFloat64s(s) 44 | fmt.Println(s) 45 | 46 | s = []float64{math.Inf(1), math.NaN(), math.Inf(-1), 0.0} // unsorted 47 | selectionAlg.SortFloat64s(s) 48 | fmt.Println(s) 49 | 50 | // Output: 51 | // [-3.8 -1.3 0.7 2.6 5.2] 52 | // [NaN -Inf 0 +Inf] 53 | } 54 | func ExampleInsertion_float64s() { 55 | s := []float64{5.2, -1.3, 0.7, -3.8, 2.6} // unsorted 56 | insertionAlg.SortFloat64s(s) 57 | fmt.Println(s) 58 | 59 | s = []float64{math.Inf(1), math.NaN(), math.Inf(-1), 0.0} // unsorted 60 | insertionAlg.SortFloat64s(s) 61 | fmt.Println(s) 62 | 63 | // Output: 64 | // [-3.8 -1.3 0.7 2.6 5.2] 65 | // [NaN -Inf 0 +Inf] 66 | } 67 | func ExampleShell_float64s() { 68 | s := []float64{5.2, -1.3, 0.7, -3.8, 2.6} // unsorted 69 | shellAlg.SortFloat64s(s) 70 | fmt.Println(s) 71 | 72 | s = []float64{math.Inf(1), math.NaN(), math.Inf(-1), 0.0} // unsorted 73 | shellAlg.SortFloat64s(s) 74 | fmt.Println(s) 75 | 76 | // Output: 77 | // [-3.8 -1.3 0.7 2.6 5.2] 78 | // [NaN -Inf 0 +Inf] 79 | } 80 | 81 | // strings 82 | func ExampleSelection_strings() { 83 | s := []string{"S", "O", "R", "T", "E", "X", "A", "M", "P", "L", "E"} 84 | selectionAlg.SortStrings(s) 85 | fmt.Println(s) 86 | 87 | // Output: 88 | // [A E E L M O P R S T X] 89 | } 90 | func ExampleInsertion_strings() { 91 | s := []string{"S", "O", "R", "T", "E", "X", "A", "M", "P", "L", "E"} 92 | insertionAlg.SortStrings(s) 93 | fmt.Println(s) 94 | 95 | // Output: 96 | // [A E E L M O P R S T X] 97 | } 98 | func ExampleShell_strings() { 99 | s := []string{"S", "O", "R", "T", "E", "X", "A", "M", "P", "L", "E"} 100 | shellAlg.SortStrings(s) 101 | fmt.Println(s) 102 | 103 | // Output: 104 | // [A E E L M O P R S T X] 105 | } 106 | 107 | // from file 108 | func ExampleSelection_fromFile() { 109 | in := testutil.NewIn("testdata/words3.txt") 110 | s := in.ReadAllStrings() 111 | selectionAlg.SortStrings(s) 112 | fmt.Println(s) 113 | 114 | // Output: 115 | // [all bad bed bug dad dim dug egg fee few for gig hut ilk jam jay jot joy men nob now owl rap sky sob tag tap tar tip wad was wee yes yet zoo] 116 | } 117 | func ExampleInsertion_fromFile() { 118 | in := testutil.NewIn("testdata/words3.txt") 119 | s := in.ReadAllStrings() 120 | insertionAlg.SortStrings(s) 121 | fmt.Println(s) 122 | 123 | // Output: 124 | // [all bad bed bug dad dim dug egg fee few for gig hut ilk jam jay jot joy men nob now owl rap sky sob tag tap tar tip wad was wee yes yet zoo] 125 | } 126 | func ExampleShell_fromFile() { 127 | in := testutil.NewIn("testdata/words3.txt") 128 | s := in.ReadAllStrings() 129 | shellAlg.SortStrings(s) 130 | fmt.Println(s) 131 | 132 | // Output: 133 | // [all bad bed bug dad dim dug egg fee few for gig hut ilk jam jay jot joy men nob now owl rap sky sob tag tap tar tip wad was wee yes yet zoo] 134 | } 135 | -------------------------------------------------------------------------------- /graphs/digraph/depth_first_order.go: -------------------------------------------------------------------------------- 1 | package digraph 2 | 3 | import "github.com/youngzhu/algs4-go/fund" 4 | 5 | // Depth-first orders. 6 | // DFS search visits each vertex exactly once. Three vertex orderings are of 7 | // interest in typical applications: 8 | // 1. Preorder: Put the vertex on a queue before the recursive calls 9 | // 2. Postorder: Put the vertex on a queue after the recursive calls 10 | // 3. Reverse postorder: Put the vertex on a stack after the recursive calls 11 | 12 | type DepthFirstOrder struct { 13 | marked []bool // marked[v]: has v marked 14 | pre []int // pre[v]: preorder number of v 15 | post []int // post[v]: postorder number of v 16 | preorder *fund.Queue // vertices in preorder 17 | postorder *fund.Queue // vertices in postorder 18 | preCounter int // counter for preorder numbering 19 | postCounter int // counter for postorder numbering 20 | } 21 | 22 | func NewDepthFirstOrder(g IDigraph) DepthFirstOrder { 23 | n := g.V() 24 | marked := make([]bool, n) 25 | pre := make([]int, n) 26 | post := make([]int, n) 27 | preorder := fund.NewQueue() 28 | postorder := fund.NewQueue() 29 | 30 | dfo := &DepthFirstOrder{ 31 | marked: marked, 32 | pre: pre, 33 | post: post, 34 | preorder: preorder, 35 | postorder: postorder} 36 | 37 | for v := 0; v < n; v++ { 38 | if !dfo.marked[v] { 39 | dfo.dfs(g, v) 40 | } 41 | } 42 | 43 | return *dfo 44 | } 45 | 46 | func NewDepthFirstOrderWeighted(g EdgeWeightedDigraph) DepthFirstOrder { 47 | n := g.V() 48 | marked := make([]bool, n) 49 | pre := make([]int, n) 50 | post := make([]int, n) 51 | preorder := fund.NewQueue() 52 | postorder := fund.NewQueue() 53 | 54 | dfo := &DepthFirstOrder{ 55 | marked: marked, 56 | pre: pre, 57 | post: post, 58 | preorder: preorder, 59 | postorder: postorder} 60 | 61 | for v := 0; v < n; v++ { 62 | if !dfo.marked[v] { 63 | dfo.dfsWeighted(g, v) 64 | } 65 | } 66 | 67 | return *dfo 68 | } 69 | 70 | func (dfo *DepthFirstOrder) dfs(g IDigraph, v int) { 71 | dfo.marked[v] = true 72 | dfo.pre[v] = dfo.preCounter 73 | dfo.preCounter++ 74 | dfo.preorder.Enqueue(v) 75 | 76 | for _, it := range g.Adj(v) { 77 | w := it.(int) 78 | if !dfo.marked[w] { 79 | dfo.dfs(g, w) 80 | } 81 | } 82 | 83 | dfo.postorder.Enqueue(v) 84 | dfo.post[v] = dfo.postCounter 85 | dfo.postCounter++ 86 | } 87 | 88 | func (dfo *DepthFirstOrder) dfsWeighted(g EdgeWeightedDigraph, v int) { 89 | dfo.marked[v] = true 90 | dfo.pre[v] = dfo.preCounter 91 | dfo.preCounter++ 92 | dfo.preorder.Enqueue(v) 93 | 94 | for _, it := range g.Adj(v) { 95 | e := it.(*DirectedEdge) 96 | w := e.To() 97 | if !dfo.marked[w] { 98 | dfo.dfsWeighted(g, w) 99 | } 100 | } 101 | 102 | dfo.postorder.Enqueue(v) 103 | dfo.post[v] = dfo.postCounter 104 | dfo.postCounter++ 105 | } 106 | 107 | // Returns the preorder number of vertex v 108 | func (dfo DepthFirstOrder) Pre(v int) int { 109 | dfo.validateVertex(v) 110 | return dfo.pre[v] 111 | } 112 | 113 | // Returns the postorder number of vertex v 114 | func (dfo DepthFirstOrder) Post(v int) int { 115 | dfo.validateVertex(v) 116 | return dfo.post[v] 117 | } 118 | 119 | // Return the vertices in postorder 120 | func (dfo DepthFirstOrder) Postorder() fund.Iterator { 121 | return dfo.postorder.Iterator() 122 | } 123 | 124 | // Return the vertices in preorder 125 | func (dfo DepthFirstOrder) Preorder() fund.Iterator { 126 | return dfo.preorder.Iterator() 127 | } 128 | 129 | // Return the vertices in reverse postorder 130 | func (dfo DepthFirstOrder) ReversePostorder() fund.Iterator { 131 | reverse := fund.NewStack() 132 | for _, v := range dfo.Postorder() { 133 | reverse.Push(v) 134 | } 135 | return reverse.Iterator() 136 | } 137 | 138 | func (t DepthFirstOrder) validateVertex(v int) { 139 | if v < 0 || v >= len(t.marked) { 140 | panic("invalidate vertex") 141 | } 142 | } --------------------------------------------------------------------------------