分享
  1. 首页
  2. 文章

Go实战--golang中各种排序算法实现以及生成随机数

wangshubo1989 · · 1555 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

生命不止,继续 go go go !!!

排序,对于每种编程语言都是要面对的。这里跟大家一起分享golang实现一些排序算法,并且说明如何生成随机数。
当然,golang为我们提供了sort包,也提供了math/rand包,这就大大方便了我们。

还要说明一下,这里不会详细介绍各种排序算法的原理,如需探索自行Google。

sort package

Package sort provides primitives for sorting slices and user-defined collections.
golang中也实现了排序算法的包sort包.

type Interface

type Interface interface {
 Len() int // Len 为集合内元素的总数
 Less(i, j int) bool //如果index为i的元素小于index为j的元素,则返回true,否则返回false
 Swap(i, j int) // Swap 交换索引为 i 和 j 的元素
}

sort相关的一些方法:
func Float64s(a []float64)
将类型为float64的slice a以升序方式进行排序

func Float64sAreSorted(a []float64) bool
判定是否已经进行排序func Ints(a []int)

func Ints(a []int)
以升序排列 int 切片。

func IntsAreSorted(a []int) bool
判断 int 切片是否已经按升序排列。

func IsSorted(data Interface) bool
判断数据是否已经排序。包括各种可sort的数据类型的判断.

func Strings(a []string)
以升序排列 string 切片。

func StringsAreSorted(a []string) bool
判断 string 切片是否已经按升序排列。

func Sort(data Interface)
对 data 进行排序(不保证相等元素的相对顺序不变)
data 默认为升序,执行 Reverse 后为降序。

func Stable(data Interface)
对 data 进行排序(保证相等元素的相对顺序不变)
data 默认为升序,执行 Reverse 后为降序。

func Reverse(data Interface) Interface
将 data 的排序动作更改为降序,Reverse 并不改变元素顺序,只改变排序行为。
更改操作不可逆,更改后的对象不可以再次 Reverse。

应用:

package main
import (
 "fmt"
 "sort"
)
type Person struct {
 Name string
 Age int
}
func (p Person) String() string {
 return fmt.Sprintf("%s: %d", p.Name, p.Age)
}
// ByAge implements sort.Interface for []Person based on
// the Age field.
type ByAge []Person
func (a ByAge) Len() int { return len(a) }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func main() {
 people := []Person{
 {"Bob", 31},
 {"John", 42},
 {"Michael", 17},
 {"Jenny", 26},
 }
 fmt.Println(people)
 sort.Sort(ByAge(people))
 fmt.Println(people)
}

search相关的方法

func Search(n int, f func(int) bool) int

search使用二分法进行查找

Search 常用于在一个已排序的,可索引的数据结构中寻找索引为 i 的值 x,例如数组或切片。这种情况下,实参 f,一般是一个闭包,会捕获所要搜索的值,以及索引并排序该数据结构的方式。

func SearchFloat64s(a []float64, x float64) int

SearchFloat64s 在float64s切片中搜索x并返回索引如Search函数所述. 返回可以插入x值的索引位置,如果x不存在,返回数组a的长度切片必须以升序排列

func SearchInts(a []int, x int) int

SearchInts 在ints切片中搜索x并返回索引如Search函数所述. 返回可以插入x值的索引位置,如果x不存在,返回数组a的长度切片必须以升序排列

func SearchStrings(a []string, x string) int

SearchFloat64s 在strings切片中搜索x并返回索引如Search函数所述. 返回可以插入x值的索引位置,如果x不存在,返回数组a的长度切片必须以升序排列

应用:

func main() {
 a := sort.StringSlice{"hello", "world", "golang", "sort", "nice"}
 a.Sort() // 二分法必须先排序
  // 获取首字母大于 n 的元素中最小的
 i := sort.Search(len(a), func(i int) bool {
 return len(a[i]) > 0 && a[i][0] > 'n'
 })
  // 显示找到的元素
 fmt.Println(a[i]) // sort
}

math/rand package

Package rand implements pseudo-random number generators.
这里的方法相对简单,就不详细介绍了,可以去看官方文档:
https://golang.org/pkg/math/rand/

下面介绍一下应用:
生成不重复的随机数

func generateRandomNumber(start int, end int, count int) []int {
 if end < start || (end-start) < count {
 return nil
 }
 nums := make([]int, 0)
 r := rand.New(rand.NewSource(time.Now().UnixNano()))
 for len(nums) < count {
 num := r.Intn((end - start)) + start
 exist := false
 for _, v := range nums {
 if v == num {
 exist = true
 break
 }
 }
 if !exist {
 nums = append(nums, num)
 }
 }
 return nums
}

各种排序算法时间及比较

冒泡排序
冒泡排序(Bubble Sort,台湾译为:泡沫排序或气泡排序)是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端。
这里写图片描述

func bubbleSort(items []int) {
 var (
 n = len(items)
 swapped = true
 )
 for swapped {
 swapped = false
 for i := 0; i < n-1; i++ {
 if items[i] > items[i+1] {
 items[i+1], items[i] = items[i], items[i+1]
 swapped = true
 }
 }
 n = n - 1
 }
}

使用sort包:

func bubbleSortUsingSortPackage(data sort.Interface) {
 r := data.Len() - 1
 for i := 0; i < r; i++ {
 for j := r; j > i; j-- {
 if data.Less(j, j-1) {
 data.Swap(j, j-1)
 }
 }
 }
}

插入排序
插入排序(Insertion Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

func insertionSort(items []int) {
 var n = len(items)
 for i := 1; i < n; i++ {
 j := i
 for j > 0 {
 if items[j-1] > items[j] {
 items[j-1], items[j] = items[j], items[j-1]
 }
 j = j - 1
 }
 }
}

使用sort包:

func insertionSortUsingSortPackage(data sort.Interface) {
 r := data.Len() - 1
 for i := 1; i <= r; i++ {
 for j := i; j > 0 && data.Less(j, j-1); j-- {
 data.Swap(j, j-1)
 }
 }
}

选择排序
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾。以此类推,直到所有元素均排序完毕。
这里写图片描述

func selectionSort(items []int) {
 var n = len(items)
 for i := 0; i < n; i++ {
 var minIdx = i
 for j := i; j < n; j++ {
 if items[j] < items[minIdx] {
 minIdx = j
 }
 }
 items[i], items[minIdx] = items[minIdx], items[i]
 }
}

使用sort包:

func selectionSortUsingSortPackage(data sort.Interface) {
 r := data.Len() - 1
 for i := 0; i < r; i++ {
 min := i
 for j := i + 1; j <= r; j++ {
 if data.Less(j, min) {
 min = j
 }
 }
 data.Swap(i, min)
 }
}

快速排序
快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来,且在大部分真实世界的数据,可以决定设计的选择,减少所需时间的二次方项之可能性。
这里写图片描述

func QuickSort(src []int, first, last int) {
 flag := first
 left := first
 right := last
 if first >= last {
 return
 }
 for first < last {
 for first < last {
 if src[last] >= src[flag] {
 last -= 1
 continue
 } else {
 tmp := src[last]
 src[last] = src[flag]
 src[flag] = tmp
 flag = last
 break
 }
 }
 for first < last {
 if src[first] <= src[flag] {
 first += 1
 continue
 } else {
 tmp := src[first]
 src[first] = src[flag]
 src[flag] = tmp
 flag = first
 break
 }
 }
 }
 QuickSort(src, left, flag-1)
 QuickSort(src, flag+1, right)
}

希尔排序
希尔排序,也称递减增量排序算法,是插入排序的一种高速而稳定的改进版本。

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

1、插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率

2、但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位>
这里写图片描述

func shellshort(items []int) {
 var (
 n = len(items)
 gaps = []int{1}
 k = 1
 )
 for {
 gap := pow(2, k) + 1
 if gap > n-1 {
 break
 }
 gaps = append([]int{gap}, gaps...)
 k++
 }
 for _, gap := range gaps {
 for i := gap; i < n; i += gap {
 j := i
 for j > 0 {
 if items[j-gap] > items[j] {
 items[j-gap], items[j] = items[j], items[j-gap]
 }
 j = j - gap
 }
 }
 }
}
func pow(a, b int) int {
 p := 1
 for b > 0 {
 if b&1 != 0 {
 p *= a
 }
 b >>= 1
 a *= a
 }
 return p
}

梳排序

func combsort(items []int) {
 var (
 n = len(items)
 gap = len(items)
 shrink = 1.3
 swapped = true
 )
 for swapped {
 swapped = false
 gap = int(float64(gap) / shrink)
 if gap < 1 {
 gap = 1
 }
 for i := 0; i+gap < n; i++ {
 if items[i] > items[i+gap] {
 items[i+gap], items[i] = items[i], items[i+gap]
 swapped = true
 }
 }
 }
}

归并排序
归并排序(Merge sort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用
这里写图片描述

func mergeSort(items []int) []int {
 var n = len(items)
 if n == 1 {
 return items
 }
 middle := int(n / 2)
 var (
 left = make([]int, middle)
 right = make([]int, n-middle)
 )
 for i := 0; i < n; i++ {
 if i < middle {
 left[i] = items[i]
 } else {
 right[i-middle] = items[i]
 }
 }
 return merge(mergeSort(left), mergeSort(right))
}
func merge(left, right []int) (result []int) {
 result = make([]int, len(left)+len(right))
 i := 0
 for len(left) > 0 && len(right) > 0 {
 if left[0] < right[0] {
 result[i] = left[0]
 left = left[1:]
 } else {
 result[i] = right[0]
 right = right[1:]
 }
 i++
 }
 // Either left or right may have elements left; consume them.
 // (Only one of the following loops will actually be entered.)
 for j := 0; j < len(left); j++ {
 result[i] = left[j]
 i++
 }
 for j := 0; j < len(right); j++ {
 result[i] = right[j]
 i++
 }
 return
}

完整代码

package main
import (
 "fmt"
 "math/rand"
 "sort"
 "time"
)
func main() {
 rand_numbs := generateRandomNumber(0, 30000, 10000)
 items_bubble := rand_numbs
 items_bubble2 := rand_numbs
 items_selection := rand_numbs
 items_selection2 := rand_numbs
 items_insertion := rand_numbs
 items_insertion2 := rand_numbs
 items_quick := rand_numbs
 items_quick2 := rand_numbs
 items_shell := rand_numbs
 items_comb := rand_numbs
 items_merge := rand_numbs
 start := time.Now()
 bubbleSort(items_bubble)
 elapsed := time.Since(start)
 fmt.Printf("Cost time bubbleSort %v\n", elapsed)
 start = time.Now()
 bubbleSortUsingSortPackage(sort.IntSlice(items_bubble2))
 end := time.Now()
 fmt.Printf("Cost time bubbleSortUsingSortPackage %v\n", end.Sub(start))
 start = time.Now()
 selectionSort(items_selection)
 end = time.Now()
 fmt.Printf("Cost time selectionSort %v\n", end.Sub(start))
 start = time.Now()
 selectionSortUsingSortPackage(sort.IntSlice(items_selection2))
 end = time.Now()
 fmt.Printf("Cost time selectionSortUsingSortPackage %v\n", end.Sub(start))
 start = time.Now()
 insertionSort(items_insertion)
 end = time.Now()
 fmt.Printf("Cost time insertionSort %v\n", end.Sub(start))
 start = time.Now()
 insertionSortUsingSortPackage(sort.IntSlice(items_insertion2))
 end = time.Now()
 fmt.Printf("Cost time insertionSortUsingSortPackage %v\n", end.Sub(start))
 start = time.Now()
 QuickSort(items_quick, 0, len(items_quick)-1)
 end = time.Now()
 fmt.Printf("Cost time QuickSort %v\n", end.Sub(start))
 start = time.Now()
 sort.Ints(items_quick2)
 end = time.Now()
 fmt.Printf("Cost time sort.Ints %v\n", end.Sub(start))
 start = time.Now()
 shellshort(sort.IntSlice(items_shell))
 end = time.Now()
 fmt.Printf("Cost time shellshort %v\n", end.Sub(start))
 start = time.Now()
 combsort(sort.IntSlice(items_comb))
 end = time.Now()
 fmt.Printf("Cost time combsort %v\n", end.Sub(start))
 start = time.Now()
 mergeSort(sort.IntSlice(items_merge))
 end = time.Now()
 fmt.Printf("Cost time mergeSort %v\n", end.Sub(start))
}
func bubbleSort(items []int) {
 var (
 n = len(items)
 swapped = true
 )
 for swapped {
 swapped = false
 for i := 0; i < n-1; i++ {
 if items[i] > items[i+1] {
 items[i+1], items[i] = items[i], items[i+1]
 swapped = true
 }
 }
 n = n - 1
 }
}
func bubbleSortUsingSortPackage(data sort.Interface) {
 r := data.Len() - 1
 for i := 0; i < r; i++ {
 for j := r; j > i; j-- {
 if data.Less(j, j-1) {
 data.Swap(j, j-1)
 }
 }
 }
}
func selectionSort(items []int) {
 var n = len(items)
 for i := 0; i < n; i++ {
 var minIdx = i
 for j := i; j < n; j++ {
 if items[j] < items[minIdx] {
 minIdx = j
 }
 }
 items[i], items[minIdx] = items[minIdx], items[i]
 }
}
func selectionSortUsingSortPackage(data sort.Interface) {
 r := data.Len() - 1
 for i := 0; i < r; i++ {
 min := i
 for j := i + 1; j <= r; j++ {
 if data.Less(j, min) {
 min = j
 }
 }
 data.Swap(i, min)
 }
}
func insertionSort(items []int) {
 var n = len(items)
 for i := 1; i < n; i++ {
 j := i
 for j > 0 {
 if items[j-1] > items[j] {
 items[j-1], items[j] = items[j], items[j-1]
 }
 j = j - 1
 }
 }
}
func insertionSortUsingSortPackage(data sort.Interface) {
 r := data.Len() - 1
 for i := 1; i <= r; i++ {
 for j := i; j > 0 && data.Less(j, j-1); j-- {
 data.Swap(j, j-1)
 }
 }
}
func QuickSort(src []int, first, last int) {
 flag := first
 left := first
 right := last
 if first >= last {
 return
 }
 for first < last {
 for first < last {
 if src[last] >= src[flag] {
 last -= 1
 continue
 } else {
 tmp := src[last]
 src[last] = src[flag]
 src[flag] = tmp
 flag = last
 break
 }
 }
 for first < last {
 if src[first] <= src[flag] {
 first += 1
 continue
 } else {
 tmp := src[first]
 src[first] = src[flag]
 src[flag] = tmp
 flag = first
 break
 }
 }
 }
 QuickSort(src, left, flag-1)
 QuickSort(src, flag+1, right)
}
func shellshort(items []int) {
 var (
 n = len(items)
 gaps = []int{1}
 k = 1
 )
 for {
 gap := pow(2, k) + 1
 if gap > n-1 {
 break
 }
 gaps = append([]int{gap}, gaps...)
 k++
 }
 for _, gap := range gaps {
 for i := gap; i < n; i += gap {
 j := i
 for j > 0 {
 if items[j-gap] > items[j] {
 items[j-gap], items[j] = items[j], items[j-gap]
 }
 j = j - gap
 }
 }
 }
}
func pow(a, b int) int {
 p := 1
 for b > 0 {
 if b&1 != 0 {
 p *= a
 }
 b >>= 1
 a *= a
 }
 return p
}
func combsort(items []int) {
 var (
 n = len(items)
 gap = len(items)
 shrink = 1.3
 swapped = true
 )
 for swapped {
 swapped = false
 gap = int(float64(gap) / shrink)
 if gap < 1 {
 gap = 1
 }
 for i := 0; i+gap < n; i++ {
 if items[i] > items[i+gap] {
 items[i+gap], items[i] = items[i], items[i+gap]
 swapped = true
 }
 }
 }
}
func mergeSort(items []int) []int {
 var n = len(items)
 if n == 1 {
 return items
 }
 middle := int(n / 2)
 var (
 left = make([]int, middle)
 right = make([]int, n-middle)
 )
 for i := 0; i < n; i++ {
 if i < middle {
 left[i] = items[i]
 } else {
 right[i-middle] = items[i]
 }
 }
 return merge(mergeSort(left), mergeSort(right))
}
func merge(left, right []int) (result []int) {
 result = make([]int, len(left)+len(right))
 i := 0
 for len(left) > 0 && len(right) > 0 {
 if left[0] < right[0] {
 result[i] = left[0]
 left = left[1:]
 } else {
 result[i] = right[0]
 right = right[1:]
 }
 i++
 }
 // Either left or right may have elements left; consume them.
 // (Only one of the following loops will actually be entered.)
 for j := 0; j < len(left); j++ {
 result[i] = left[j]
 i++
 }
 for j := 0; j < len(right); j++ {
 result[i] = right[j]
 i++
 }
 return
}
func generateRandomNumber(start int, end int, count int) []int {
 if end < start || (end-start) < count {
 return nil
 }
 nums := make([]int, 0)
 r := rand.New(rand.NewSource(time.Now().UnixNano()))
 for len(nums) < count {
 num := r.Intn((end - start)) + start
 exist := false
 for _, v := range nums {
 if v == num {
 exist = true
 break
 }
 }
 if !exist {
 nums = append(nums, num)
 }
 }
 return nums
}

这里写图片描述


有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:wangshubo1989

查看原文:Go实战--golang中各种排序算法实现以及生成随机数

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1555 次点击 ∙ 1 赞
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏