

使用 Go 实现快速排序
source link: http://colobu.com/2018/06/26/implement-quick-sort-in-golang/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

快速排序(quick sort)号称是二十世纪最伟大的十大算法之一( The Best of the 20th Century: Editors Name Top 10 Algorithms ), 但是快速排序也是最不容易实现的排序算法之一 ()。虽然它的原理非常的简单,但实现起来很容易出错。 也曾因为快排导致腥风血雨甚至网站攻击事件。
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
分治法:将问题分解为若干个规模更小但结构与原问题相似的子问题。递归地解这些子问题,然后将这些子问题的解组合为原问题的解。
利用分治法可将快速排序的分为三步:
- 在数据集之中,选择一个元素作为”基准”(pivot)。
- 所有小于”基准”的元素,都移到”基准”的左边;所有大于”基准”的元素,都移到”基准”的右边。这个操作称为分区 (partition) 操作,分区操作结束后,基准元素所处的位置就是最终排序后它的位置。
- 对”基准”左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。
快速排序平均时间复杂度为 O(n log n)
,最坏情况为 O(n2)
,不稳定排序。
快速排序一般实现为原地排序(in-place),因为非原地排序会设计到大量的容器创建和对象复制。
本文实现了两种快速排序,一种是单线程的快速排序,一种是一定数量的goroutine并行的快速排序。
同时也增加了标准库排序算法和timsort算法的比较。
下面是算法实现:
package main import ( "fmt" "math/rand" "sort" "time" "github.com/psilva261/timsort" ) func partition(a []int, lo, hi int) int { pivot := a[hi] i := lo -1 for j := lo; j < hi; j++ { if a[j] < pivot { i++ a[j], a[i] = a[i], a[j] } } a[i+1], a[hi] = a[hi], a[i+1] return i +1 } func quickSort(a []int, lo, hi int) { if lo >= hi { return } p := partition(a, lo, hi) quickSort(a, lo, p-1) quickSort(a, p+1, hi) } func quickSort_go(a []int, lo, hi int, done chan struct{}, depth int) { if lo >= hi { done <- struct{}{} return } depth-- p := partition(a, lo, hi) if depth >0 { childDone := make(chan struct{},2) go quickSort_go(a, lo, p-1, childDone, depth) go quickSort_go(a, p+1, hi, childDone, depth) <-childDone <-childDone } else { quickSort(a, lo, p-1) quickSort(a, p+1, hi) } done <- struct{}{} } func main() { rand.Seed(time.Now().UnixNano()) testData1, testData2, testData3, testData4 := make([]int,0,100000000), make([]int,0,100000000), make([]int,0,100000000), make([]int,0,100000000) times :=100000000 for i :=0; i < times; i++ { val := rand.Intn(20000000) testData1 = append(testData1, val) testData2 = append(testData2, val) testData3 = append(testData3, val) testData4 = append(testData4, val) } start := time.Now() quickSort(testData1,0, len(testData1)-1) fmt.Println("single goroutine: ", time.Now().Sub(start)) if !sort.IntsAreSorted(testData1) { fmt.Println("wrong quick_sort implementation") } done := make(chan struct{}) start = time.Now() go quickSort_go(testData2,0, len(testData2)-1, done,5) <-done fmt.Println("multiple goroutine: ", time.Now().Sub(start)) if !sort.IntsAreSorted(testData2) { fmt.Println("wrong quickSort_go implementation") } start = time.Now() sort.Ints(testData3) fmt.Println("std lib: ", time.Now().Sub(start)) if !sort.IntsAreSorted(testData3) { fmt.Println("wrong std lib implementation") } start = time.Now() timsort.Ints(testData4, func(a, b int) bool { return a <= b }) fmt.Println("timsort: ", time.Now().Sub(start)) if !sort.IntsAreSorted(testData4) { fmt.Println("wrong timsort implementation") } }
Recommend
-
100
数据结构与算法—快速排序(Java实现)
-
147
面试官系列(番外): 别再使用阮一峰版的快速排序了 往期 面试官系列(1): 如何实现深克隆 面试官系列(2): Event Bus的实现 面试官系列(3): 前端路由的实现 面试官系列(4): 实现双向绑定Proxy比defineproperty优劣如何
-
26
算法原理 下列动图来自 @五分钟学算法 ,演示了快速排序算法的原理和步骤。 步骤: 从数组中选...
-
38
快速排序 快速排序思路 快速排序通过分支法的思想,从一个数组中选取一个基准元素pivot,把这个数组中小于pivot的移动到左边,把大于pivot的移动到右边。然后再分别对左右两边数组进行快速排序。 双边循环法
-
37
快速排序 快速排序效率高,空间复杂度底,在工作中一般是用的最多的排序算法,所以需要掌握。 在看快速排序之前,先看一下另一个比快排简单点的问题,就是荷兰国旗问题 给定一个数组arr,和一个数num,请把小于n...
-
4
PHP之快速排序的实现 发表于 2017-12-28 | 分类于 开发 | | 浏览4 次 | 字数统计: 382 | 阅读时长 ≈ 1快速排序(Quicksort)是对冒泡排序的一种改进。快速排序由C. A....
-
2
使用 Lambda 实现超强的排序功能 作者:看山灬 2022-09-20 08:49:26 本文演示了使用 Java8 中使用 Lambda 表达式实现各种排序逻辑,新增的语法糖真香。
-
6
快速排序(Quicksort)的Javascript实现 浏览:9765次 出处信息 日本程序员norahiko,写了一个...
-
9
快速排序 C实现 首页 分...
-
9
快速排序算法Java、Python、Go和Rust四种代码实现 快速排序...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK