冒泡排序:

时间复杂度:O(n^2)
稳定性:稳定

  1. //冒泡排序
  2. //相邻两位交换,12交换,23交换,34交换,把最大的数放到最右边
  3. //利用flag标记可以避免无效循环
  4. func BubbleSort(arr []int) {
  5. length := len(arr)
  6. //length是最后一位,i < length-1,查询到倒数第二位
  7. for i := 0; i < length-1; i++ {
  8. //true表示此次循环没有发生交换
  9. flag := true
  10. //每次循环j都从0开始,然后j++
  11. //每次循环最大的数都会被放到最右边,j的查询范围在逐渐减小,所以j < length-1-i
  12. for j := 0; j < length-1-i; j++ {
  13. if arr[j] > arr[j+1] {
  14. arr[j], arr[j+1] = arr[j+1], arr[j]
  15. //false表示此次循环发生了交换
  16. flag = false
  17. }
  18. }
  19. //true表示序列已经有序,直接退出,不用继续循环
  20. //false表示本次循环发生了交换,需要继续判断下个循环
  21. if flag {
  22. break
  23. }
  24. }
  25. }
简单选择排序:

时间复杂度:O(n^2)
稳定性:不稳定

  1. //简单选择排序
  2. //循环一遍,把最小的放最左边;循环剩下的序列
  3. //循环时只取值比较,一遍循环完发生交换
  4. func selectSort(arr []int) {
  5. length := len(arr)
  6. for i := 0; i < length; i++ {
  7. //从首位i开始,最小指向i,依次与后面比较
  8. min := i
  9. for j := i + 1; j < length; j++ {
  10. //j比首位小,把最小指向j
  11. if arr[min] > arr[j] {
  12. min = j
  13. }
  14. }
  15. //循环完一遍,最小值发生过变化
  16. if min != i {
  17. //交换i和min
  18. arr[i], arr[min] = arr[min], arr[i]
  19. }
  20. }
  21. }
直接插入排序:

时间复杂度:O(n^2)
稳定性:稳定

  1. //直接插入排序
  2. //取首元素作为有序队列,把第二位插入到有序队列中,把第三位插入到前两位组成的有序队列中
  3. //新的一位插入有序队列时,跟他的前一位比较,即有序队列的最右边,依次向前遍历
  4. func insertSort(arr []int) {
  5. length := len(arr)
  6. //从第二位开始处理,所以i从1开始
  7. for i := 1; i < length; i++ {
  8. //if满足,则新的一位需要插入处理;else表示新的一位依旧有序,不处理
  9. if arr[i] < arr[i-1] {
  10. //arr[i]插入时,前面的元素需要后移,i位置元素被顶掉,所以需要临时存值
  11. temp := arr[i]
  12. //j取有序队列的最右位i-1,依次向左j--
  13. j := i - 1
  14. //temp < arr[j],把j向后移位,依次循环,直到temp >= arr[j]
  15. for ; j >= 0 && temp < arr[j]; j-- {
  16. //把j向后移位
  17. arr[j+1] = arr[j]
  18. }
  19. //因为发生了j--
  20. arr[j+1] = temp
  21. }
  22. }
  23. }
希尔排序:

时间复杂度:O(n^1.5)
稳定性:不稳定

  1. //希尔排序
  2. //按间隔分组,每组进行插入排序
  3. //长度为10,间隔为10/2=5,按(0,5)(1,6)(2,7)(3,8)(4,9)分组
  4. //间隔减小为5/2=2,按(0,2,4,6,8)(1,3,5,7,9)分组
  5. //组内插入排序时,各组之间交替比较,以间隔为2举例:先比较0和2,再比较1和3,再比较4,再比较5,依次遍历
  6. //直到间隔为1,按(0,1...9)分组
  7. func shellSsort(arr []int) {
  8. length := len(arr)
  9. //按间隔分组
  10. for gap := length / 2; gap > 0; gap /= 2 {
  11. //当前各个分组进行插入排序
  12. for i := gap; i < length; i++ {
  13. if arr[i] < arr[i-gap] {
  14. temp := arr[i]
  15. j := i - gap
  16. for ; j >= 0 && temp < arr[j]; j -= gap {
  17. arr[j+gap] = arr[j]
  18. }
  19. arr[j+gap] = temp
  20. }
  21. }
  22. }
  23. }
归并排序:

时间复杂度:O(nlogn)
稳定性:稳定

  1. //归并排序
  2. //将两个有序序列合并成一个有序序列
  3. //取中间值分左右递归处理
  4. func mergeSort(r []int) []int {
  5. length := len(r)
  6. if length <= 1 {
  7. return r
  8. }
  9. //左右分别处理
  10. num := length / 2
  11. left := mergeSort(r[:num])
  12. right := mergeSort(r[num:])
  13. //左右两边都为有序,进行合并
  14. return merge(left, right)
  15. }
  16. func merge(left, right []int) (result []int) {
  17. l, r := 0, 0
  18. //left或right有一方遍历完则退出循环
  19. for l < len(left) && r < len(right) {
  20. if left[l] < right[r] {
  21. result = append(result, left[l])
  22. l++
  23. } else {
  24. result = append(result, right[r])
  25. r++
  26. }
  27. }
  28. //left和right均为有序,直接将剩余部分加进序列
  29. //如果上面是left遍历完,left[l:]为[],right还有剩余值
  30. //如果上面是right遍历完,right[r:]为[], left还有剩余值
  31. result = append(result, left[l:]...)
  32. result = append(result, right[r:]...)
  33. return
  34. }
快速排序:

时间复杂度:O(nlogn)
稳定性:不稳定

  1. //快速排序
  2. //取首位元素为临界值,一遍循环,临界值左边为小数,右边为大数
  3. //递归临界值左边和右边
  4. func quickSort(arr []int) {
  5. length := len(arr)
  6. if length <= 1 {
  7. return
  8. }
  9. quick(arr, 0, length-1)
  10. }
  11. func quick(arr []int, start, end int) {
  12. if start >= end {
  13. return
  14. }
  15. i, j := start, end
  16. //取首位元素为分界值
  17. temp := arr[i]
  18. for i < j {
  19. //从右往左找,大的不处理,j--
  20. for i < j && arr[j] >= temp {
  21. j--
  22. }
  23. //直到遇见第一个小的,跳出上面循环
  24. if i < j {
  25. //把小的给i,temp的值没发生变化
  26. arr[i] = arr[j]
  27. i++
  28. }
  29. //从左往右找,小的不处理,i++
  30. for i < j && arr[i] <= temp {
  31. i++
  32. }
  33. //直到遇见第一个大的,跳出上面循环
  34. if i < j {
  35. //把大的给j,temp的值没发生变化
  36. arr[j] = arr[i]
  37. j--
  38. }
  39. }
  40. //把temp给到i位置
  41. arr[i] = temp
  42. //递归i的左边,0到i-1
  43. quick(arr, start, i-1)
  44. //递归i的右边,i+1到right
  45. quick(arr, i+1, end)
  46. }
堆排序:

时间复杂度:O(nlogn)
稳定性:不稳定

  1. //堆排序
  2. //升序使用大顶堆,降序使用小顶堆,以大顶堆为例
  3. //顶堆是上下比较大小,父结点与其孩子比较,同一父结点的左右大小无限制,二叉搜索树是左右比较大小,不要搞混
  4. //先调整序列为大顶堆(序列默认是一棵二叉树,把该二叉树调整为大顶堆)
  5. //处理大顶堆:首尾交换,末位最大,去掉末位,调整剩下序列为大顶堆,循环处理
  6. func heapSort(arr []int) []int {
  7. length := len(arr)
  8. //调整序列为大顶堆
  9. for i := length/2 - 1; i >= 0; i-- {
  10. //从最后一个非叶子结点开始,从右往左,从下往上,length/2-1为最后一个非叶子结点
  11. adjustHeap(arr, i, length)
  12. }
  13. //处理大顶堆
  14. //大顶堆左右无序,上下有序
  15. for i := length - 1; i > 0; i-- {
  16. //首位最大,首尾交换,把最大放在队尾
  17. arr[0], arr[i] = arr[i], arr[0]
  18. //去掉队尾最大元素,所以队列长度length-1,即为i,把剩余i个元素调整为大顶堆
  19. //此时只有刚交换的首位不符合大顶堆条件,没必要像上面循环所有非叶子结点,只需从首位开始调整,所以i=0
  20. adjustHeap(arr, 0, i)
  21. }
  22. return arr
  23. }
  24. //调整二叉树为大顶堆
  25. func adjustHeap(arr []int, i, length int) {
  26. //非叶子结点i的左右孩子
  27. left := 2*i + 1
  28. right := 2*i + 2
  29. //默认i为最大
  30. max := i
  31. //存在左孩子且左孩子大,最大指向left,因为右孩子可能更大,所以暂不交换
  32. if left < length && arr[left] > arr[max] {
  33. max = left
  34. }
  35. //存在右孩子且右孩子更大,最大指向right
  36. if right < length && arr[right] > arr[max] {
  37. max = right
  38. }
  39. //最大发生过改变,交换
  40. if max != i {
  41. arr[i], arr[max] = arr[max], arr[i]
  42. //最后一层非叶子结点,递归时不发生交换操作;
  43. //假如二叉树深度为4,最后一层非叶子结点为第三层,处理第二层发生交换时,需要递归处理第三层是否被影响了
  44. adjustHeap(arr, max, length)
  45. }
  46. }
基数排序:

时间复杂度:O(d(n+r))
稳定性:稳定

  1. //基数排序
  2. //分配式排序,桶子法,非负数,共0-9,10个桶子
  3. //首次循环根据元素个位数,将元素分配至对应桶子里,0进0号桶,9进9号桶
  4. //按桶子排序,再次循环,根据元素十位数再次分配
  5. func radixSort(arr []int) {
  6. length := len(arr)
  7. if length <= 1 {
  8. return
  9. }
  10. //元素的最大位数
  11. d := maxBit(arr)
  12. //用mod和dev求对应位数上的数值
  13. mod, dev := 10, 1
  14. //循环位数
  15. for i := 0; i < d; i++ {
  16. //10个桶子
  17. temp := [10][]int{}
  18. //遍历序列
  19. for j := 0; j < length; j++ {
  20. //先求余,再求商
  21. //个位数值:x%10/1;十位数值:x%100/10
  22. bucket := arr[j] % mod / dev
  23. //按位存值
  24. temp[bucket] = append(temp[bucket], arr[j])
  25. }
  26. //为arr排序时的下标
  27. k := 0
  28. //排序arr
  29. for m := 0; m < 10; m++ {
  30. for n := 0; n < len(temp[m]); n++ {
  31. arr[k] = temp[m][n]
  32. k++
  33. }
  34. }
  35. //为下一位做准备
  36. mod *= 10
  37. dev *= 10
  38. }
  39. }
  40. //基数排序
  41. //分配式排序,桶子法,存在负数,共0-19,20个桶子
  42. //首次循环根据元素个位数,将元素分配至对应桶子里,-9进1号桶,-1进9号桶,0进10号桶,1进11号桶,19进19号桶
  43. //按桶子排序,再次循环,根据元素十位数再次分配
  44. func radixSort(arr []int) {
  45. length := len(arr)
  46. if length <= 1 {
  47. return
  48. }
  49. //元素的最大位数
  50. d := maxBit(arr)
  51. //用mod和dev求对应位数上的数值
  52. mod, dev := 10, 1
  53. //循环位数
  54. for i := 0; i < d; i++ {
  55. //10个桶子
  56. temp := [20][]int{}
  57. //遍历序列
  58. for j := 0; j < length; j++ {
  59. //先求余,再求商,下标不为负,+10保证为非负数
  60. //个位数值:x%10/1+10;十位数值:x%100/10+10
  61. bucket := (arr[j] % mod / dev)+10
  62. //按位存值
  63. temp[bucket] = append(temp[bucket], arr[j])
  64. }
  65. //为arr排序时的下标
  66. k := 0
  67. //排序arr
  68. for m := 0; m < 20; m++ {
  69. for n := 0; n < len(temp[m]); n++ {
  70. arr[k] = temp[m][n]
  71. k++
  72. }
  73. }
  74. //为下一位做准备
  75. mod *= 10
  76. dev *= 10
  77. }
  78. }
  79. //元素的最大位数
  80. func maxBit(arr []int) int {
  81. length := len(arr)
  82. d := 1
  83. p := 10
  84. for i := 0; i < length; i++ {
  85. for arr[i] >= p {
  86. d++
  87. p *= 10
  88. }
  89. }
  90. return d
  91. }

公众号:李田路口

Go语言实现:常见排序算法的更多相关文章

  1. [算法] 常见排序算法总结(C语言版)

    常见排序算法总结 本文对比较常用且比较高效的排序算法进行了总结和解析,并贴出了比较精简的实现代码,包括选择排序.插入排序.归并排序.希尔排序.快速排序等.算法性能比较如下图所示: 1 冒泡排序 基本原 ...

  2. 常见排序算法(附java代码)

    常见排序算法与java实现 一.选择排序(SelectSort) 基本原理:对于给定的一组记录,经过第一轮比较后得到最小的记录,然后将该记录与第一个记录的位置进行交换:接着对不包括第一个记录以外的其他 ...

  3. JS常见排序算法

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. JavaScript版几种常见排序算法

    今天发现一篇文章讲“JavaScript版几种常见排序算法”,看着不错,推荐一下原文:http://www.w3cfuns.com/blog-5456021-5404137.html 算法描述: * ...

  5. 常见排序算法(JS版)

    常见排序算法(JS版)包括: 内置排序,冒泡排序,选择排序,插入排序,希尔排序,快速排序(递归 & 堆栈),归并排序,堆排序,以及分析每种排序算法的执行时间. index.html <! ...

  6. 常见排序算法-Python实现

    常见排序算法-Python实现 python 排序 算法 1.二分法     python    32行 right = length-  :  ]   ):  test_list = [,,,,,, ...

  7. python常见排序算法解析

    python——常见排序算法解析   算法是程序员的灵魂. 下面的博文是我整理的感觉还不错的算法实现 原理的理解是最重要的,我会常回来看看,并坚持每天刷leetcode 本篇主要实现九(八)大排序算法 ...

  8. python——常见排序算法解析

    算法是程序员的灵魂. 下面的博文是我整理的感觉还不错的算法实现 原理的理解是最重要的,我会常回来看看,并坚持每天刷leetcode 本篇主要实现九(八)大排序算法,分别是冒泡排序,插入排序,选择排序, ...

  9. 常见排序算法总结 -- java实现

    常见排序算法总结 -- java实现 排序算法可以分为两大类: 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序. 线性时间 ...

  10. 常见排序算法题(java版)

    常见排序算法题(java版) //插入排序:   package org.rut.util.algorithm.support;   import org.rut.util.algorithm.Sor ...

随机推荐

  1. 比特币学习笔记(二)---在windows下调试比特币源码

    根据我一贯的学习经验,学习开源代码的话,单单看是不够的,必须一边看一边调试才能尽快理解,所以我们要想法搭建windows下bitcoin源码的调试环境. 紧接着昨天的进度,想要调试linux下的比特币 ...

  2. UML之类之间的关系

    UML 简介 统一建模语言(Unified Modeling Language,UML) 作用:对软件系统进行说明 如果说软件系统是一本小说的话,那么 UML 就是将小说动漫化. 也许你看过这本小说, ...

  3. 使用gravatar生成头像

    avatar代表您在线的图像,当你与网站互动时,你的名字旁边会出现一张图片. Gravatar是一个全球通用的头像.你只需上传一次并创建自己的个人资料,然后当你加入任何支持Gravatar的网站时,你 ...

  4. Spring学习记录2——简单了解Spring容器工作机制

    简单的了解Spring容器内部工作机制 Spring的AbstractApplicationContext是ApplicationContext的抽象实现类,该抽象类的refresh()方法定义了Sp ...

  5. Java 遍历集合时产生的ConcurrentModificationException异常

    前几天做Java实验的时候,打算用foreach遍历一个ArrayList集合,并且当集合中的某个元素符合某个值时删除这个元素.写完运行时抛出了ConcurrentModificationExcept ...

  6. SliverAppBar 介绍及使用

    SliverAppBar控件可以实现页面头部区域展开.折叠的效果,类似于Android中的CollapsingToolbarLayout.先看下SliverAppBar实现的效果,效果图如下: Sli ...

  7. 架构师JavaScript 的对象继承方式,有几种程序写法?

    架构师JavaScript 的对象继承方式,有几种程序写法?   一.对象冒充 其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式).因为构造函数只是一个函数, ...

  8. Spring(二)核心容器 - 简介 、BeanFactory、ApplicationContext

    目录 前言 1.容器简介 2.容器的结构 2.1 BeanFactory 2.2 ApplicationContext 2.2.1 ConfigurableApplicationContext 2.2 ...

  9. 为什么Mozilla Thunderbird无法登陆腾讯企业邮?

    (一)问题描述 登陆腾讯企业邮提示"无法登录到服务器.可能是配置.用户名或者密码错误." (二)解决方案 手动配置 IMAP | imap.exmail.qq.com | 993 ...

  10. LeetCode 第七题--整数反转

    1. 题目 2.思路 1. 题目 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例 1: 输入: 123输出: 321 示例 2: 输入: -123输出: -321示例 ...