Go 快速排序
最后修改于 2025年3月8日
本教程将探讨 Go 中的快速排序算法,展示如何按升序和降序对数字和文本数据进行排序。
一个 算法 是一个结构化的步骤序列,用于高效地解决问题或执行任务。它是编程的基石,指导着计算逻辑。
排序 是指将数据组织成特定的序列,例如升序(从小到大)或降序(从大到小)。这对于数据检索和呈现等任务至关重要。
常用排序算法
以下是一些著名的排序算法
- 快速排序
- 归并排序
- 气泡排序
- 插入排序
- 选择排序
快速排序算法
快速排序是一种分治算法,它选择一个基准元素并将数组围绕它进行分区。小于基准的元素放在左边,大于基准的元素放在右边。
子数组被递归地排序,最终得到一个完全排序的数组。其平均时间复杂度为 O(n log n),对于大多数数据集来说都很高效,尽管最坏情况是 O(n²)。
快速排序示例
下面是一个用于数字和字符串的 Go 快速排序实现。
package main import "fmt" func quickSort(arr []int) []int { if len(arr) <= 1 { return arr } pivot := arr[len(arr)/2] left := []int{} middle := []int{} right := []int{} for _, x := range arr { if x < pivot { left = append(left, x) } else if x == pivot { middle = append(middle, x) } else { right = append(right, x) } } left = quickSort(left) right = quickSort(right) return append(append(left, middle...), right...) } func quickSortStrings(arr []string) []string { if len(arr) <= 1 { return arr } pivot := arr[len(arr)/2] left := []string{} middle := []string{} right := []string{} for _, x := range arr { if x < pivot { left = append(left, x) } else if x == pivot { middle = append(middle, x) } else { right = append(right, x) } } left = quickSortStrings(left) right = quickSortStrings(right) return append(append(left, middle...), right...) } func main() { numbers := []int{3, 6, 8, 10, 1, 2, 1} sortedNumbers := quickSort(numbers) fmt.Println("Sorted numbers:", sortedNumbers) words := []string{"banana", "apple", "cherry", "date"} sortedWords := quickSortStrings(words) fmt.Println("Sorted words:", sortedWords) }
quickSort
函数用于对整数进行排序,而 quickSortStrings
用于处理字符串。两者都使用中间基准并通过递归对数据进行分区。
结果是一个新的升序排序的切片。这种方法利用了 Go 的类型系统,以简洁的方式确保了对不同数据类型的灵活性。
$ go run quick_sort.go Sorted numbers: [1 1 2 3 6 8 10] Sorted words: [apple banana cherry date]
降序排序
以下是如何在 Go 中调整快速排序以实现降序排序。
package main import "fmt" func quickSortDesc(arr []int) []int { if len(arr) <= 1 { return arr } pivot := arr[len(arr)/2] left := []int{} middle := []int{} right := []int{} for _, x := range arr { if x > pivot { left = append(left, x) } else if x == pivot { middle = append(middle, x) } else { right = append(right, x) } } left = quickSortDesc(left) right = quickSortDesc(right) return append(append(left, middle...), right...) } func quickSortStringsDesc(arr []string) []string { if len(arr) <= 1 { return arr } pivot := arr[len(arr)/2] left := []string{} middle := []string{} right := []string{} for _, x := range arr { if x > pivot { left = append(left, x) } else if x == pivot { middle = append(middle, x) } else { right = append(right, x) } } left = quickSortStringsDesc(left) right = quickSortStringsDesc(right) return append(append(left, middle...), right...) } func main() { numbers := []int{3, 6, 8, 10, 1, 2, 1} sortedNumbersDesc := quickSortDesc(numbers) fmt.Println("Sorted numbers (descending):", sortedNumbersDesc) words := []string{"banana", "apple", "cherry", "date"} sortedWordsDesc := quickSortStringsDesc(words) fmt.Println("Sorted words (descending):", sortedWordsDesc) }
quickSortDesc
和 quickSortStringsDesc
函数颠倒了分区逻辑——较大的元素放在左边,较小的元素放在右边——从而实现降序排序。
这种调整对于对项目进行从高到低排名等场景很有用,例如 Go 应用程序中的分数或字母顺序颠倒的列表。
$ go run quick_sort_desc.go Sorted numbers (descending): [10 8 6 3 2 1 1] Sorted words (descending): [date cherry banana apple]
将快速排序与插入排序进行比较
快速排序的平均 O(n log n) 性能优于插入排序的 O(n²),尤其是在大型数据集上。Go 中的这个基准测试说明了这种差异。
package main import ( "fmt" "math/rand" "time" ) func quickSort(arr []int) []int { if len(arr) <= 1 { return arr } pivot := arr[len(arr)/2] left := []int{} middle := []int{} right := []int{} for _, x := range arr { if x < pivot { left = append(left, x) } else if x == pivot { middle = append(middle, x) } else { right = append(right, x) } } left = quickSort(left) right = quickSort(right) return append(append(left, middle...), right...) } func insertionSort(arr []int) []int { result := make([]int, len(arr)) copy(result, arr) for i := 1; i < len(result); i++ { key := result[i] j := i - 1 for j >= 0 && key < result[j] { result[j+1] = result[j] j-- } result[j+1] = key } return result } func main() { rand.Seed(time.Now().UnixNano()) data := make([]int, 10000) for i := range data { data[i] = rand.Intn(1000) } quickData := make([]int, len(data)) copy(quickData, data) start := time.Now() quickSort(quickData) quickTime := time.Since(start) insertData := make([]int, len(data)) copy(insertData, data) start = time.Now() insertionSort(insertData) insertTime := time.Since(start) fmt.Printf("Quick Sort time: %.6f seconds\n", quickTime.Seconds()) fmt.Printf("Insertion Sort time: %.6f seconds\n", insertTime.Seconds()) }
此代码生成 10,000 个随机整数并计时两种算法。快速排序使用递归和分区,而插入排序逐个移动元素。
快速排序通常完成得更快——通常快一个数量级——因为它具有对数缩放。插入排序虽然更简单,但在处理大型数据时会遇到困难,因此在这里不太实用。
这些比较有助于开发人员根据 Go 项目中的数据集大小和性能需求来选择算法。
来源
本教程在 Go 中解释了快速排序,并提供了升序和降序排序的示例,以及与插入排序的基准测试。