Skip to content

Commit d075271

Browse files
committed
quick sort
1 parent e1bb82c commit d075271

File tree

13 files changed

+477
-9
lines changed

13 files changed

+477
-9
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package dijkstra
2+
3+
import (
4+
"github.com/xiaomeng79/go-algorithm/data-structures/graph"
5+
"github.com/xiaomeng79/go-algorithm/data-structures/priority_queue"
6+
)
7+
8+
//迪杰斯特拉算法计算的是从网中一个顶点到其它顶点之间的最短路径问题
9+
//http://data.biancheng.net/view/46.html
10+
11+
func ShortestPath(g *graph.UnGraph, source graph.VertexId) map[graph.VertexId]graph.VertexId {
12+
visited := make(map[graph.VertexId]bool, g.VerticesCount())
13+
dist := make(map[graph.VertexId]int)
14+
prev := make(map[graph.VertexId]graph.VertexId)
15+
Q := priority_queue.NewMin()
16+
vertices := g.VerticesIter()
17+
18+
dist[source] = 0
19+
for vertex := range vertices {
20+
if source != vertex {
21+
dist[vertex] = 1000
22+
prev[vertex] = 0
23+
}
24+
Q.Insert(*priority_queue.NewItem(vertex, dist[vertex]))
25+
}
26+
27+
for Q.Len() > 0 {
28+
u := Q.Extract().Value.(graph.VertexId)
29+
visited[u] = true
30+
31+
for neighbour := range g.GetNeighbours(u).VerticesIter() {
32+
if !visited[neighbour] {
33+
alt := dist[u] + g.GetEdgeWeight(u, neighbour)
34+
35+
if alt < dist[neighbour] {
36+
dist[neighbour] = alt
37+
prev[neighbour] = u
38+
Q.ChangePriority(neighbour, alt)
39+
}
40+
}
41+
}
42+
}
43+
return prev
44+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package dijkstra
2+
3+
import (
4+
"fmt"
5+
"github.com/xiaomeng79/go-algorithm/data-structures/graph"
6+
"testing"
7+
)
8+
9+
func TestShortestPath(t *testing.T) {
10+
h := graph.NewUndirected()
11+
12+
for i := 0; i < 5; i++ {
13+
h.AddVertex(graph.VertexId(i))
14+
}
15+
16+
h.AddEdge(graph.VertexId(0), graph.VertexId(1), 10)
17+
h.AddEdge(graph.VertexId(1), graph.VertexId(2), 20)
18+
h.AddEdge(graph.VertexId(2), graph.VertexId(3), 40)
19+
h.AddEdge(graph.VertexId(0), graph.VertexId(2), 50)
20+
h.AddEdge(graph.VertexId(0), graph.VertexId(3), 80)
21+
h.AddEdge(graph.VertexId(0), graph.VertexId(4), 10)
22+
h.AddEdge(graph.VertexId(4), graph.VertexId(3), 10)
23+
24+
prev := ShortestPath(h, graph.VertexId(0))
25+
fmt.Println(prev)
26+
if prev[1] != graph.VertexId(0) ||
27+
prev[2] != graph.VertexId(1) ||
28+
prev[3] != graph.VertexId(4) ||
29+
prev[4] != graph.VertexId(0) {
30+
31+
fmt.Println(prev)
32+
t.Error()
33+
}
34+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package topological
2+
3+
import (
4+
"github.com/xiaomeng79/go-algorithm/data-structures/graph"
5+
"github.com/xiaomeng79/go-algorithm/data-structures/stack"
6+
)
7+
8+
//拓扑排序指的是将有向无环图(又称“DAG”图)中的顶点按照图中指定的先后顺序进行排序。
9+
10+
//拓扑排序实质上就是一种偏序到全序的排序算法
11+
12+
//应用场景:排课问题,课程有依赖关系
13+
14+
//对有向无环图进行拓扑排序,只需要遵循两个原则:
15+
//在图中选择一个没有前驱的顶点 V;
16+
//从图中删除顶点 V 和所有以该顶点为尾的弧。
17+
18+
func Sort(g *graph.DirGraph) *stack.Stack {
19+
var visit func(v graph.VertexId)
20+
sorted := stack.New()
21+
visited := make(map[graph.VertexId]bool)
22+
marked := make(map[graph.VertexId]bool)
23+
24+
visit = func(v graph.VertexId) {
25+
//判断是不是一个无环图
26+
if marked[v] {
27+
panic("not a DAG")
28+
}
29+
marked[v] = true
30+
//获取出度的顶点
31+
successors := g.GetSuccessors(v).VerticesIter()
32+
for successor := range successors {
33+
if !marked[successor] && !visited[successor] {
34+
visit(successor)
35+
}
36+
}
37+
visited[v] = true
38+
marked[v] = false
39+
sorted.Push(int(v))
40+
}
41+
42+
vertices := g.VerticesIter()
43+
for vertex := range vertices {
44+
if !visited[vertex] {
45+
visit(vertex)
46+
}
47+
}
48+
49+
return sorted
50+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package topological
2+
3+
import (
4+
"fmt"
5+
"github.com/xiaomeng79/go-algorithm/data-structures/graph"
6+
"testing"
7+
)
8+
9+
func TestSort(t *testing.T) {
10+
h := graph.NewDirected()
11+
12+
h.AddVertex(graph.VertexId(2))
13+
h.AddVertex(graph.VertexId(3))
14+
h.AddVertex(graph.VertexId(5))
15+
h.AddVertex(graph.VertexId(7))
16+
h.AddVertex(graph.VertexId(8))
17+
h.AddVertex(graph.VertexId(9))
18+
h.AddVertex(graph.VertexId(10))
19+
h.AddVertex(graph.VertexId(11))
20+
21+
h.AddEdge(graph.VertexId(7), graph.VertexId(8), 1)
22+
h.AddEdge(graph.VertexId(7), graph.VertexId(11), 1)
23+
h.AddEdge(graph.VertexId(5), graph.VertexId(11), 1)
24+
h.AddEdge(graph.VertexId(3), graph.VertexId(8), 1)
25+
h.AddEdge(graph.VertexId(3), graph.VertexId(10), 1)
26+
h.AddEdge(graph.VertexId(8), graph.VertexId(9), 1)
27+
h.AddEdge(graph.VertexId(11), graph.VertexId(10), 1)
28+
h.AddEdge(graph.VertexId(11), graph.VertexId(2), 1)
29+
h.AddEdge(graph.VertexId(11), graph.VertexId(9), 1)
30+
31+
s := Sort(h)
32+
i, _ := s.Pop()
33+
first := graph.VertexId(i)
34+
if first != 7 &&
35+
first != 5 &&
36+
first != 3 {
37+
fmt.Print(first, first != 7)
38+
t.Error()
39+
}
40+
41+
}

algorithms/sort/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@
1010
排序则必有先后大小高低,基本操作是:将元素通过比较来调整位置。
1111

1212
排序本质是消除逆序。采用“交换相邻元素”的办法来消除逆序,每次正好只消除一个,因此必须执行O(N^2)的交换次数。
13-
基于交换元素的排序要想突破这个下界,必须执行一些比较,交换相隔比较远的元素,使得一次交换能消除一个以上的逆序。这样才能降低时间复杂度。
13+
基于交换元素的排序要想突破这个下界,必须执行一些比较,交换相隔比较远的元素,使得一次交换能消除一个以上的逆序。这样才能降低时间复杂度。
14+
15+
![时间复杂度](https://github.com/hustcc/JS-Sorting-Algorithm/raw/master/res/sort.png)

algorithms/sort/bubble/bubble.go

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,32 @@ package bubble
99
//3. 针对所有的元素重复以上的步骤,除了最后一个。
1010
//4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
1111

12-
func BubbleSort(arr []int) []int {
13-
length := len(arr) //获取最大长度
14-
for i := 0; i < length; i++ { //比较次数
15-
for j := 0; j < length-1-i; j++ { //比较长度
16-
if arr[j] > arr[j+1] {
17-
arr[j], arr[j+1] = arr[j+1], arr[j]
12+
//时间复杂度:O(n²)
13+
14+
//推荐
15+
func BubbleSort(arr []int) {
16+
for itemCount := len(arr) - 1; ; itemCount-- {
17+
swap := false //下一次判断是否发生交换,没交换,说明已经有序
18+
for i := 1; i <= itemCount; i++ {
19+
if arr[i-1] > arr[i] {
20+
arr[i-1], arr[i] = arr[i], arr[i-1]
21+
swap = true
1822
}
1923
}
24+
if swap == false {
25+
break
26+
}
2027
}
21-
return arr
2228
}
29+
30+
//func BubbleSort(arr []int) []int {
31+
// length := len(arr) //获取最大长度
32+
// for i := 0; i < length; i++ { //比较次数
33+
// for j := 0; j < length-1-i; j++ { //比较长度
34+
// if arr[j] > arr[j+1] {
35+
// arr[j], arr[j+1] = arr[j+1], arr[j]
36+
// }
37+
// }
38+
// }
39+
// return arr
40+
//}

algorithms/sort/bubble/bubble_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import (
99

1010
func TestBubbleSort(t *testing.T) {
1111
for _, v := range testdata.Values {
12-
assert.Exactly(t, v.Sort, BubbleSort(v.Nosort), "no eq")
12+
BubbleSort(v.Nosort)
13+
assert.Exactly(t, v.Sort, v.Nosort, "no eq")
1314
}
1415
}
1516

algorithms/sort/heap/heap.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package heap
2+
3+
import "github.com/xiaomeng79/go-algorithm/data-structures/heap"
4+
5+
//堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法
6+
//堆排序的平均时间复杂度为 Ο(nlogn)
7+
8+
func HeapSort(arr []int) []int {
9+
h := heap.NewMin()
10+
for i := 0; i < len(arr); i++ {
11+
h.Insert(heap.Int(arr[i]))
12+
}
13+
14+
for i := 0; i < len(arr); i++ {
15+
arr[i] = int(h.Extract().(heap.Int))
16+
}
17+
return arr
18+
}

algorithms/sort/heap/heap_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package heap
2+
3+
import (
4+
"github.com/stretchr/testify/assert"
5+
"github.com/xiaomeng79/go-algorithm/algorithms/sort/testdata"
6+
"github.com/xiaomeng79/go-algorithm/algorithms/sort/utils"
7+
"testing"
8+
)
9+
10+
func TestHeapSort(t *testing.T) {
11+
for _, v := range testdata.Values {
12+
assert.Exactly(t, v.Sort, HeapSort(v.Nosort), "no eq")
13+
}
14+
}
15+
16+
func benchmarkHeapSort(n int, b *testing.B) {
17+
b.StopTimer()
18+
list := utils.GetArrayOfSize(n)
19+
b.ReportAllocs()
20+
b.StartTimer()
21+
for i := 0; i < b.N; i++ {
22+
HeapSort(list)
23+
}
24+
}
25+
26+
func BenchmarkHeapSort100(b *testing.B) { benchmarkHeapSort(100, b) }
27+
func BenchmarkHeapSort1000(b *testing.B) { benchmarkHeapSort(1000, b) }
28+
func BenchmarkHeapSort10000(b *testing.B) { benchmarkHeapSort(10000, b) }
29+
30+
//func BenchmarkHeapSort100000(b *testing.B) { benchmarkHeapSort(100000, b) }

algorithms/sort/quick/quick.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package quick
2+
3+
//快速排序:快速排序应该算是在冒泡排序基础上的递归分治法
4+
5+
//算法步骤:
6+
//从数列中挑出一个元素,称为 “基准”(pivot);
7+
//
8+
//重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
9+
//
10+
//递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;
11+
//
12+
//递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
13+
14+
func QuickSort(arr []int) []int {
15+
return quickSort(arr, 0, len(arr)-1)
16+
}
17+
18+
func quickSort(arr []int, left, right int) []int {
19+
if left < right {
20+
partitionIndex := partition(arr, left, right)
21+
quickSort(arr, left, partitionIndex-1)
22+
quickSort(arr, partitionIndex+1, right)
23+
}
24+
return arr
25+
}
26+
27+
func partition(arr []int, left, right int) int {
28+
pivot := left
29+
index := pivot + 1
30+
31+
for i := index; i <= right; i++ {
32+
if arr[i] < arr[pivot] {
33+
swap(arr, i, index)
34+
index += 1
35+
}
36+
}
37+
swap(arr, pivot, index-1)
38+
return index - 1
39+
40+
}
41+
42+
func swap(arr []int, i, j int) {
43+
arr[i], arr[j] = arr[j], arr[i]
44+
}

0 commit comments

Comments
 (0)