Golang 桶排序
最后修改于 2025 年 3 月 9 日
本教程深入探讨 Golang 中的桶排序算法。我们将探索升序和降序排列数字和文本,并使用基准测试将其与快速排序进行比较。
算法 是解决问题或完成任务的一组结构化步骤。它是编程和计算机科学的基石。
排序 将数据组织成特定的序列,例如升序或降序。这对于程序中高效的数据处理和分析至关重要。
常用排序算法
以下是一些流行的排序算法
- 气泡排序
- 选择排序
- 插入排序
- 归并排序
- 快速排序
- 桶排序
桶排序算法
桶排序是一种基于分布的排序方法。它将元素分成“桶”,对每个桶进行单独排序,然后将它们合并。当数据在范围内均匀分布时,它表现出色。
与基于比较的排序不同,它依赖于数据分布,因此对于均匀分布来说速度很快,但否则效果较差。
桶排序示例:数值数据
这是 Golang 中用于升序排列数字的桶排序实现。
bucket_sort_numeric.go
package main
import (
"fmt"
"sort"
)
func bucketSort(arr []float64) []float64 {
if len(arr) == 0 {
return arr
}
maxVal := arr[0]
for _, val := range arr {
if val > maxVal {
maxVal = val
}
}
bucketSize := maxVal / float64(len(arr))
buckets := make([][]float64, len(arr))
for i := range buckets {
buckets[i] = []float64{}
}
for _, num := range arr {
idx := int(num / bucketSize)
if idx >= len(arr) {
idx = len(arr) - 1
}
buckets[idx] = append(buckets[idx], num)
}
for i := range buckets {
sort.Float64s(buckets[i])
}
result := []float64{}
for _, bucket := range buckets {
result = append(result, bucket...)
}
return result
}
func main() {
arr := []float64{0.42, 0.32, 0.33, 0.52, 0.37, 0.47, 0.51}
sorted := bucketSort(arr)
fmt.Println("Sorted array:", sorted)
}
这使用桶排序对浮点数切片进行排序。它使用 Go 的 sort.Float64s 对每个桶进行排序。
$ go run bucket_sort_numeric.go Sorted array: [0.32 0.33 0.37 0.42 0.47 0.51 0.52]
桶排序示例:文本数据
这是一个使用桶排序以降序排列字符串的长度的示例。
bucket_sort_textual.go
package main
import (
"fmt"
"sort"
)
func bucketSortTextual(arr []string) []string {
if len(arr) == 0 {
return arr
}
maxLen := 0
for _, s := range arr {
if len(s) > maxLen {
maxLen = len(s)
}
}
buckets := make([][]string, maxLen+1)
for i := range buckets {
buckets[i] = []string{}
}
for _, s := range arr {
buckets[len(s)] = append(buckets[len(s)], s)
}
for i := range buckets {
sort.Sort(sort.Reverse(sort.StringSlice(buckets[i])))
}
result := []string{}
for i := len(buckets) - 1; i >= 0; i-- {
result = append(result, buckets[i]...)
}
return result
}
func main() {
arr := []string{"apple", "banana", "kiwi", "mango", "pear"}
sorted := bucketSortTextual(arr)
fmt.Println("Sorted array:", sorted)
}
这会根据长度以降序排列字符串,在每个桶内按字母顺序反向排序,使用 sort.Reverse。
$ go run bucket_sort_textual.go Sorted array: [banana mango apple pear kiwi]
桶排序与快速排序的比较
桶排序在均匀分布的数据上表现出色,时间复杂度为 O(n + k),其中 k 是桶的数量。快速排序的平均时间复杂度为 O(n log n),对于一般情况更具通用性。
基准测试示例
这比较了桶排序和快速排序在大型数据集上的性能。
benchmark.go
package main
import (
"fmt"
"math/rand"
"sort"
"time"
)
func bucketSort(arr []float64) []float64 {
if len(arr) == 0 {
return arr
}
maxVal := arr[0]
for _, val := range arr {
if val > maxVal {
maxVal = val
}
}
bucketSize := maxVal / float64(len(arr))
buckets := make([][]float64, len(arr))
for i := range buckets {
buckets[i] = []float64{}
}
for _, num := range arr {
idx := int(num / bucketSize)
if idx >= len(arr) {
idx = len(arr) - 1
}
buckets[idx] = append(buckets[idx], num)
}
for i := range buckets {
sort.Float64s(buckets[i])
}
result := []float64{}
for _, bucket := range buckets {
result = append(result, bucket...)
}
return result
}
func quickSort(arr []float64) []float64 {
if len(arr) <= 1 {
return arr
}
pivot := arr[len(arr)/2]
left, middle, right := []float64{}, []float64{}, []float64{}
for _, x := range arr {
if x < pivot {
left = append(left, x)
} else if x == pivot {
middle = append(middle, x)
} else {
right = append(right, x)
}
}
return append(append(quickSort(left), middle...), quickSort(right)...)
}
func main() {
rand.Seed(time.Now().UnixNano())
arr := make([]float64, 10000)
for i := range arr {
arr[i] = rand.Float64() * 1000
}
start := time.Now()
bucketSort(append([]float64{}, arr...))
fmt.Printf("Bucket Sort Time: %.6f seconds\n", time.Since(start).Seconds())
start = time.Now()
quickSort(append([]float64{}, arr...))
fmt.Printf("Quick Sort Time: %.6f seconds\n", time.Since(start).Seconds())
}
这将在 10,000 个随机浮点数上对这两种算法进行基准测试。桶排序在均匀数据上可能会略胜一筹,但快速排序的整体一致性更好。
来源
我们已经涵盖了 Golang 中的桶排序,并将其与快速排序进行了比较。它非常适合均匀数据,而快速排序是一种健壮的通用选择。