选择排序

选择排序,一般我们指的是简单选择排序,也可以叫直接选择排序,它不像冒泡排序一样相邻地交换元素,而是通过选择最小的元素,每轮迭代只需交换一次。虽然交换次数比冒泡少很多,但效率和冒泡排序一样的糟糕。

选择排序属于选择类排序算法。

我打扑克牌的时候,会习惯性地从左到右扫描,然后将最小的牌放在最左边,然后从第二张牌开始继续从左到右扫描第二小的牌,放在最小的牌右边,以此反复。选择排序和我玩扑克时的排序特别相似。

一、算法介绍

现在有一堆乱序的数,比如:5 9 1 6 8 14 6 49 25 4 6 3

第一轮迭代,从第一个数开始,左边到右边进行扫描,找到最小的数 1,与数列里的第一个数交换位置。

第二轮迭代,从第二个数开始,左边到右边进行扫描,找到第二小的数 3,与数列里的第二个数交换位置。

第三轮迭代,从第三个数开始,左边到右边进行扫描,找到第三小的数 4,与数列里的第三个数交换位置。

第N轮迭代:....

经过交换,最后的结果为:1 3 4 5 6 6 6 8 9 14 25 49,我们可以看到已经排好序了。

每次扫描数列找出最小的数,然后与第一个数交换,然后排除第一个数,从第二个数开始重复这个操作,这种排序叫做简单选择排序。

举个简单例子,选择排序一个 4 个元素的数列:4 2 9 1

[]表示排好序

起始: 4 2 9 1  未排序数列从左扫描最小的数是 1,与第一个元素 4 交换,交换 1,4
一轮: [1] 2 9 4 未排序数列从左扫描最小的数是 2,不需要交换
二轮: [1 2] 9 4 未排序数列从左扫描最小的数是 4,与第三个元素 9 交换,交换 4,9
三轮: [1 2 4] 9 未排序数列只有 1 个数,结束
结果: [1 2 4 9]

比较的次数和冒泡排序一样多,因为扫描过程也是比较的过程,只不过交换的次数减少为每轮 1 次。最佳和最坏时间复杂度仍然是:O(n^2)

选择排序是一个不稳定的排序算法,比如数组:[5 6 5 1],第一轮迭代时最小的数是1,那么与第一个元素5交换位置,这样数字1就和数字5交换了位置,导致两个相同的数字5排序后位置变了。

二、算法实现

package main

import "fmt"

func SelectSort(list []int) {
n := len(list)
// 进行 N-1 轮迭代
for i := 0; i < n-1; i++ {
// 每次从第 i 位开始,找到最小的元素
min := list[i] // 最小数
minIndex := i // 最小数的下标
for j := i + 1; j < n; j++ {
if list[j] < min {
// 如果找到的数比上次的还小,那么最小的数变为它
min = list[j]
minIndex = j
}
} // 这一轮找到的最小数的下标不等于最开始的下标,交换元素
if i != minIndex {
list[i], list[minIndex] = list[minIndex], list[i]
}
}
} func main() {
list := []int{5, 9, 1, 6, 8, 14, 6, 49, 25, 4, 6, 3}
SelectSort(list)
fmt.Println(list)
}

每进行一轮迭代,我们都会维持这一轮最小数:min和最小数的下标:minIndex,然后开始扫描,如果扫描的数比该数小,那么替换掉最小数和最小数下标,扫描完后判断是否应交换,然后交换:list[i], list[minIndex] = list[minIndex], list[i]

三、算法改进

上面的算法需要从某个数开始,一直扫描到尾部,我们可以优化算法,使得复杂度减少一半。

我们每一轮,除了找最小数之外,还找最大数,然后分别和前面和后面的元素交换,这样循环次数减少一半,如:

package main

import "fmt"

func SelectGoodSort(list []int) {
n := len(list) // 只需循环一半
for i := 0; i < n/2; i++ {
minIndex := i // 最小值下标
maxIndex := i // 最大值下标 // 在这一轮迭代中要找到最大值和最小值的下标
for j := i + 1; j < n-i; j++ {
// 找到最大值下标
if list[j] > list[maxIndex] {
maxIndex = j // 这一轮这个是大的,直接 continue
continue
}
// 找到最小值下标
if list[j] < list[minIndex] {
minIndex = j
}
} if maxIndex == i && minIndex != n-i-1 {
// 如果最大值是开头的元素,而最小值不是最尾的元素
// 先将最大值和最尾的元素交换
list[n-i-1], list[maxIndex] = list[maxIndex], list[n-i-1]
// 然后最小的元素放在最开头
list[i], list[minIndex] = list[minIndex], list[i]
} else if maxIndex == i && minIndex == n-i-1 {
// 如果最大值在开头,最小值在结尾,直接交换
list[minIndex], list[maxIndex] = list[maxIndex], list[minIndex]
} else {
// 否则先将最小值放在开头,再将最大值放在结尾
list[i], list[minIndex] = list[minIndex], list[i]
list[n-i-1], list[maxIndex] = list[maxIndex], list[n-i-1]
}
}
} func main() {
list := []int{5}
SelectGoodSort(list)
fmt.Println(list) list1 := []int{5, 9}
SelectGoodSort(list1)
fmt.Println(list1) list2 := []int{5, 9, 1}
SelectGoodSort(list2)
fmt.Println(list2) list3 := []int{5, 9, 1, 6, 8, 14, 6, 49, 25, 4, 6, 3}
SelectGoodSort(list3)
fmt.Println(list3) list4 := []int{5, 9, 1, 6, 8, 14, 6, 49, 25, 4, 6}
SelectGoodSort(list4)
fmt.Println(list4)
}

输出:

[5]
[5 9]
[1 5 9]
[1 3 4 5 6 6 6 8 9 14 25 49]
[1 4 5 6 6 6 8 9 14 25 49]

优化后的选择排序还是很慢,它很好理解,但是还是不建议在工程上使用。

系列文章入口

我是陈星星,欢迎阅读我亲自写的 数据结构和算法(Golang实现),文章首发于 阅读更友好的GitBook

数据结构和算法(Golang实现)(20)排序算法-选择排序的更多相关文章

  1. 数据结构和算法(Golang实现)(26)查找算法-哈希表

    哈希表:散列查找 一.线性查找 我们要通过一个键key来查找相应的值value.有一种最简单的方式,就是将键值对存放在链表里,然后遍历链表来查找是否存在key,存在则更新键对应的值,不存在则将键值对链 ...

  2. 数据结构和算法(Golang实现)(27)查找算法-二叉查找树

    二叉查找树 二叉查找树,又叫二叉排序树,二叉搜索树,是一种有特定规则的二叉树,定义如下: 它是一颗二叉树,或者是空树. 左子树所有节点的值都小于它的根节点,右子树所有节点的值都大于它的根节点. 左右子 ...

  3. 数据结构和算法(Golang实现)(28)查找算法-AVL树

    AVL树 二叉查找树的树高度影响了查找的效率,需要尽量减小树的高度,AVL树正是这样的树. 一.AVL树介绍 AVL树是一棵严格自平衡的二叉查找树,1962年,发明者Adelson-Velsky和La ...

  4. 数据结构和算法(Golang实现)(29)查找算法-2-3树和左倾红黑树

    某些教程不区分普通红黑树和左倾红黑树的区别,直接将左倾红黑树拿来教学,并且称其为红黑树,因为左倾红黑树与普通的红黑树相比,实现起来较为简单,容易教学.在这里,我们区分开左倾红黑树和普通红黑树. 红黑树 ...

  5. 算法与数据结构(十三) 冒泡排序、插入排序、希尔排序、选择排序(Swift3.0版)

    本篇博客中的代码实现依然采用Swift3.0来实现.在前几篇博客连续的介绍了关于查找的相关内容, 大约包括线性数据结构的顺序查找.折半查找.插值查找.Fibonacci查找,还包括数结构的二叉排序树以 ...

  6. java排序算法(二):直接选择排序

    java排序算法(二) 直接选择排序 直接选择排序排序的基本操作就是每一趟从待排序的数据元素中选出最小的(或最大的)一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完,它需要经过n- ...

  7. 排序(Sort)-----选择排序

       声明:文中动画转载自https://blog.csdn.net/qq_34374664/article/details/79545940    1.选择排序简介 选择排序(Select Sort ...

  8. 选择排序—简单选择排序(Simple Selection Sort)

    基本思想: 在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换:然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素 ...

  9. 选择排序—简单选择排序(Simple Selection Sort)原理以及Java实现

    基本思想: 在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换:然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素 ...

随机推荐

  1. Core3.1WebApi_ 同源策略_如何支持跨域(转载)

    原文:https://mp.weixin.qq.com/s/id3fOyGrZI9lLx7PKbVYlg

  2. Rust入坑指南:齐头并进(下)

    前文中我们聊了Rust如何管理线程以及如何利用Rust中的锁进行编程.今天我们继续学习并发编程, 原子类型 许多编程语言都会提供原子类型,Rust也不例外,在前文中我们聊了Rust中锁的使用,有了锁, ...

  3. mysql查询性能问题,加了order by速度慢了

    关于order by的查询优化可以看一下: MySQL ORDER BY/LIMIT performance: late row lookups 主要介绍了两个方法: 第一个是FORCE INDEX ...

  4. NLP interview

    2019-08-26 17:19:58 1)聊实习项目 2)代码题,二维数组中的查找某个target 3)讲一些最能体现创新能力的工作,而不是一些工程上的实现 4)讲论文可以从哪些方面做创新点,文本生 ...

  5. 最新SCI影响因子发布!Nature屠榜,AI领域Top 1000期刊盘点

    [导读]2018年度SCI期刊影响因子最新发布,Nature.Science.Cell三大神刊排名前列.新智元摘取其中有关人工智能.机器学习.计算机视觉.机器人学等领域的期刊并做简要介绍,希望对读者选 ...

  6. Azure Web: 数据库的创建与数据监控

    介绍主题:Azure 大家都知道Azure云现在由于中国国策不一样,会有中国版Azure云和国际版Azure. 但是我们今天基于这个国际版的讲,因为我这个博客会比较international一点.(- ...

  7. 关于getchar的疑惑

    最近做了一道题,我的代码有片段是这样的 while(scanf("%d",&n)) { if(n==0&&getchar()=='\n') break; . ...

  8. Java基础语法(11)-面向对象之关键字

    title: Java基础语法(11)-面向对象之关键字 blog: CSDN data: Java学习路线及视频 1.this this是什么 它在方法内部使用,即这个方法所属对象的引用: clas ...

  9. coding++ :在引入的css或者js文件后面加参数的作用

    前沿: 有些小伙伴们在页面(F12)直接对 JS.CSS 文件进行编辑.或者打断点调试的时候 可能会发现 所有的操作都不生效,为什么? 原因可能存在以下情况 有时候可能会遇到js或者css文件引用后传 ...

  10. iOS 构建动态库

    一.构建步骤 创建一个动态库 MyDynamicFramework 创建一个测试类 在 MyDynamicFramework.h(默认生成,可统一暴露头文件) 中 #import "Pers ...