点击上方“五分钟学算法”,选择“星标”公众号

重磅干货,第一时间送达




选择排序思想

选择排序(Selection Sort)的基本思想是不断地从数组当中未排序的部分选取关键字最小的记录,并将该记录作为已排序部分的最后一个记录(考虑升序排列的情况)。算法主要就是维护一个给定数组的两个子数组:

  1. 数组已排序的部分;
  2. 数组未排序的部分;

在选择排序的每一次迭代中,从数组中未排序的部分选择出最小元素(升序排列的情况),然后将其移入数组已排序的部分。

初始时,给定一个数组,且将该数组当中的所有元素都被划分为无序部分:


遍历数组 [0,7],找到下标为 5 最小的关键字 13:


下标为 5 最小的关键字 13 与下标为 0 的关键字 49 进行交换,这样就得到了数组有序部分的第一个关键字 13,而无序部分相应的减少了一个关键:

之后的所有操作和之前一样,在无序部分找到最小的关键字,然后与无序部分的第一个关键字交换,有序部分加一,无序部分减一:

简而言之,选择排序就两步:

  1. 选择最小(或最大)
  2. 交换

实现代码

C 实现

void swap(int *xp, int *yp) {  int temp = *xp;  *xp = *yp;  *yp = temp; } 

void selectionSort(int arr[], int n) {  int i, j, min_idx; 

 // i就相当于将数组划分为有序部分和无序部分的边界,不断地让这个边界后移 for (i = 0; i -1; i++)  {   //找到数组中无序部分的最小关键字  min_idx = i;   for (j = i+1; j   if (arr[j]    min_idx = j; 

  // 将最小关键字与无序部分的第一给关键字交换  swap(&arr[min_idx], &arr[i]);  } } 

Java实现

class SelectionSort {  void sort(int arr[]) {   int n = arr.length; 

  for (int i = 0; i 1; i++)   {    int min_idx = i;    for (int j = i+1; j                 if (arr[j]      min_idx = j;             } 

   int temp = arr[min_idx];    arr[min_idx] = arr[i];    arr[i] = temp;   }  } } 

Python实现

def SelectionSort(A):    for i in range(len(A)):         min_idx = i         for j in range(i+1, len(A)):             if A[min_idx] > A[j]:                 min_idx = j 

        A[i], A[min_idx] = A[min_idx], A[i]     return A

复杂度分析

时间复杂度

上面的循环中的 if 语句最坏情况下一共计算了多少次?

当 i == 0 的时候,j 的取值范围是从 1 到 n -1,内循环的判断一种执行了 n - 1 次;

当 i == 1 的时候,j 的取值范围是从 2 到 n -1,内循环的判断一种执行了 n - 2 次;

以此类推......

当 i 取最大值 n - 2 时,j 的取值为 n -1,内循环的判断执行了1 次;

所以,整体内循环的判断语句执行次数就是:1 + 2 + 3 + ... + (n - 2) + (n - 1) 。

这种计算一个高斯公式搞定,则 if 执行了就是 次,时间复杂度为 量级。

空间复杂度

选择排序属于原地排序(In-place Sorting),因为选择排序没有使用任何额外的空间,仅使用了数组自身所占用的空间,所以空间复杂度就是 。你也可以认为原地排序算法就是空间复杂度为 的算法。

稳定性分析

关于排序算法的稳定性问题,景禹在之前的一篇文章 排序算法的稳定性 中有分享,这里我们就直接分析选择排序的稳定性问题。

我可以直接告诉你选择排序的默认实现方式是不稳定的,具体为神马,我们接着看一个例子:


给定上面一个数组,我们按照前面的实现方式进行排序。

第一步:在数组中找到最小的关键字 1 ,并与数组中的第一个元素(红色色块 4)交换位置:


第二步:在数组中无序部分 [5,3,2,4,4] 找到最小的关键字 2 与无序部分的第一个关键字 5 交换位置:


第三步:在数组中无序部分 [3,5,4,4] 中找到最小的关键字 3 和无序部分的第一个关键字 3 交换,和之前一样:


第四步:在数组中无序部分 [5,4,4] 中找到最小的关键字 4(注意是蓝色色块的4)  和 5 交换:


第五步:在数组中无序部分 [5,4] 中找到最小的关键字 4(注意是红色色块的4)  和 5 交换:


此时我们得到一个有序数组,但是与原始的数组相比,两个 4 的相对位置发生了变化。即,本来红色色块的 4 在蓝色色块的 4 的前面,而排序后蓝色的在红色的前面,这就是我们之前所说的不稳定(两个值相同的关键字排序前后的相对位置发生了变化)。也就是说目前的实现方式下的选择排序是不稳定的。

稳定的选择排序

不稳定的选择排序结果:


目标 -- 实现一个稳定的选择排序:


为了实现现在这一目标,我们分析一下原始的选择排序为什么不稳定?

答案就是交换操作造成了不稳定。选择排序的工作原理就是在未排序的部分找到关键字最小的元素,然后将该元素与未排序部分的第一个元素进行交换位置。也就是这个交换操作导致其不稳定,比如前面分析的时候,第一次交换就是的 4 得相对位置发生了变化。


因此可以考虑对这里的交换操作进行修改使得选择排序变得稳定。

要想每一次将最小元素放置在其位置而不进行交换,可以通过将每一次选择出的最小关键字前面的无序数组元素都向后移动一个位置,使选择排序稳定。简单来说,就是利用类似于插入排序的技术将最小的元素插入正确的位置。


第一步:找到最小元素是 1 ,此时 不再 是将红色色块 4 和最小元素 1 进行交换,而是将 1 插入到正确的位置,然后将 1 之前的每一个元素都向后移动一个位置:

第二步:找到数组无序部分的最小元素 2 ,将 2 之前的 [4,5,3] 的每一个元素向后移动一个位置:


第三步:找到数组无序部分的最小元素 3 ,将 3 之前的 [4,5] 的每一个元素向后移动一个位置:


第四步:找到数组无序部分的最小元素 4(红色色块) ,其前面没有无序元素,什么都不做;

第五步:找到数组无序部分的最小元素 4(蓝色色块) ,将其前面的元素 5 向后移动,我们得到了一个稳定的有序数组:


稳定的选择排序的实现

Java实现

class JingYuSorting {  static void stableSelectionSort(int[] a, int n) {   // 与默认的实现方式相同  for (int i = 0; i 1; i++)   {    // a[i - 1] 之前的元素为数组的有序部分    // 从 arr[i] 到 arr[n - 1] 找到最小元素的下标保存到min中   int min = i;    for (int j = i + 1; j     if (a[min] > a[j])      min = j; 

   // 将最小的元素移动到当前的位置 i.   int key = a[min];             // 将从 i 到 min - 1 的元素都向后移动一个位置   while (min > i)    {     a[min] = a[min - 1];     min--;    }    // 将当前选择的最小元素放到正确的位置   a[i] = key;   }  } } 

复杂度分析

时间复杂度

时间复杂度为 ,整体依旧是两层 for 循环嵌套。但是稳定的选择排序需要移动元素,每一次选择出一个最小元素,就需要对其前面无序的元素向后移动,最坏的情况是,第一次移动 n-1 次,第二次移动 n - 2 次,......,第 n-1 次移动 1 次,总共移动 ,这并不会影响到整个实现的时间复杂度的量级。

空间复杂度

稳定的选择排序依旧没有使用任何额外的空间,所有操作都是在数组内进行的,所以空间复杂度为 .

实战演练

给定一个字符串数组,使用选择排序对数组进行排序。

输入: paper true soap floppy flower 输出: floppy, flower, paper, soap, true

我们前面所讲的所有例子都是用整数进行说明的,这里要使用选择排序对字符串数组进行排序,我们仅需要对原始的实现中整型的比较操作和拷贝操作转化为字符串的比较和拷贝操作。

java 中字符串的比较操作使用 compareTo() 函数即可;C++/C 的比较操作可以使用 strcmp() 函数进行比较,拷贝可以使用 strcpy() 函数进行拷贝。这里就给大家提供 Java 的参考代码。

题外话:面试中,好多面试官会考察函数 strcmp()strcpy() 的底层实现,对这个点不太熟悉的小禹禹可以了解一下,觉得没时间,希望景禹解析的,评论区留下你的足迹。

// 使用选择排序对字符串数组进行排序static void selectionSort(String arr[],int n) {  // 将有序部分和无序部分的界限 i 不断向后移动 for(int i = 0; i 1; i++)  { 

  // 在数组未排序部分找到最小的字符串  int min_index = i; //保存最小的字符串的下标  String minStr = arr[i]; //保存最小的字符串  for(int j = i + 1; j   {    if(arr[j].compareTo(minStr) 0)    {     minStr = arr[j];     min_index = j;    }   }         // 将最小字符串与 位置为 i 的字符串进行交换        if(min_index != i)         {             String temp = arr[min_index];             arr[min_index] = arr[i];             arr[i] = temp;         }  } }

网站推荐

给大家推荐一个可视化网站:https://visualgo.net/zh/sorting

我们以今日的选择排序给大家讲一下使用的方法。

输入网址后,进入如下界面:


但看着密密麻麻的英文,我们直接按 ESC 键。

紧接着选择 zh ,中文模式:


导航栏中分别为:冒泡排序、选择排序(SEL)、插入排序(INS)、归并排序(MER)、

快速排序(QUI)、随机快速排序(R-Q)、计数排序(COU)、基数排序(RAD)。

我们点击 SEL,即选择排序:


默认提供了一组输入数组,你也可以通过下图中几种方式自己生成:


我们输入我们的示例输入 [4,5,3,2,4,1] :


然后就是进行选择排序了,依次点击排序→执行:


紧接着你就可以看到下面的执行动画了:


就到这里了,记得一定要自己去探索一下奥~~


推荐阅读

•   吴师兄实名吐槽 LeetCode 上的一道题目。。。•   面试字节跳动时,我竟然遇到了原题……•   Leetcode 惊现马化腾每天刷题 ?为啥大佬都这么努力!•   为什么 MySQL 使用 B+ 树•   一道简简单单的字节跳动算法面试题•   新手使用 GitHub 必备的两个神器•   卧槽!红警代码竟然开源了!!!


欢迎关注我的公众号“五分钟学算法”,如果喜欢,麻烦点一下“在看”~

js数组按中文拼音排序_这才是选择排序正确的打开方式!相关推荐

  1. js数组按中文拼音排序_学习排序算法,结合这个方法太容易理解了

    排序是一个经典的问题,它以一定的顺序对一个数组或列表中的元素进行重新排序.而排序算法也是各有千秋,每个都有自身的优点和局限性.虽然这些算法平常根本就不用自己去编写,但作为一个有追求的程序员,还是要了解 ...

  2. js数组按中文拼音排序_通俗易懂讲 Python 算法:快速排序

    原文:https://stackabuse.com/quicksort-in-python/ 作者:Marcus Sanatan 译者:老齐 欢迎在 bilibili  搜索 freeCodeCamp ...

  3. js数组按中文拼音排序_JavaScript数组

    1.什么是数组 数组是指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素,数组是一种将一组数据存储在单个变量名下的优雅方式 2.创建方式 在js中数组的创建方式有2种 a.利用 ...

  4. js数组按中文拼音排序_收藏 | JS开发必须知道的41个技巧

    作者:火狼https://cloud.tencent.com/developer/article/1666138 JS是前端的核心,但有些使用技巧你还不一定知道: 本文梳理了JS的41个技巧,帮助大家 ...

  5. adb命令怎么打开_用python撸支付宝体验金,才是程序员正确的打开方式!

    支付宝近期推出了余额宝体验金活动,这个活动有两个部分一个是邀请好友赢推荐金,另一个是鲤鱼跃龙门,点击越快体验金金额越高. 今天讲讲怎么自动化实现快速点击加速增加我们的鲤鱼跃龙门的体验金额,实现的方法有 ...

  6. python实现登录支付宝收能量_用python撸支付宝体验金,才是程序员正确的打开方式...

    支付宝近期推出了余额宝体验金活动,这个活动有两个部分一个是邀请好友赢推荐金,另一个是鲤鱼跃龙门,点击越快体验金金额越高. 今天讲讲怎么自动化实现快速点击加速增加我们的鲤鱼跃龙门的体验金额,实现的方法有 ...

  7. php 按汉字拼音排序,php 数组按中文拼音排序

    本篇文章给大家分享的内容是关于php数组按中文拼音排序,有着一定的参考价值,有需要的朋友可以参考一下 $str = "我们可以在浏览器中看到,当鼠标移到元素上时,元素开始向右移动,开始比较慢 ...

  8. c语言数组项目按身高排序,过三关 Java冒泡排序选择排序插入排序小练习

    材料:猴子排序,按照身高来从小到大来排序. 第一关: 老猴子带领小猴子队伍按大小逐一比较,交换,开始高矮排列队伍.(冒泡排序) 第二关: 太慢了,给第一关增加难度,进行选择排序 第三关: 最后,尝试选 ...

  9. [ 数据结构 -- 手撕排序算法第四篇 ] 选择排序

    手撕排序算法系列之第四篇:选择排序. 从本篇文章开始,我会介绍并分析常见的几种排序,大致包括直接插入排序,冒泡排序,希尔排序,选择排序,堆排序,快速排序,归并排序等. 大家可以点击此链接阅读其他排序算 ...

  10. 【简单排序算法】:简单选择排序、直接插入排序和冒泡排序

    [简单排序算法]:简单选择排序.直接插入排序和冒泡排序 简单选择排序: 原理:设所排序序列的记录个数为n.i取1,2,-,n-1,每次从所有n-i+1个记录(Ri,Ri+1,-,Rn)中找出最小的记录 ...

最新文章

  1. wordcloud安装失败原因和解决方法
  2. 查看OpenStack版本
  3. 在VM上安装centOS后的网络配置
  4. html5仪表板可调节,使用HTML5画布实现的超棒javascript动画仪表板:gauge.js
  5. fedora yum Another app is currently holding the yum lock
  6. 【转】OpenGL超级宝典笔记——纹理映射Mipmap
  7. 信息学奥赛一本通 1035:等差数列末项计算 | OpenJudge NOI 1.3 18
  8. aix oracle 10.2.0.1 升级 10.2.0.4,install oracle 10r2 for aix
  9. 《区块链开发指南》一一导读
  10. python软件下载安装中文版-Python3.7.6下载
  11. Linux 磁盘管理 : dir dirs dircolors 命令详解
  12. 修改服务器的返回数据,使用charles 修改服务器返回数据
  13. docker CLI官方教程 run方法解析(docer run 、docker attach 与 docker exec的区别)
  14. 一口气搞懂「Flink Metrics」监控指标和性能优化,全靠这33张图和7千字(建议收藏)
  15. 数据结构—排序(第九章)
  16. Xshell vim使用右侧数字键盘时数字变成英文字母的解决办法
  17. processing摸索前行(01)
  18. 【转载】好电影!保存了,没事干的时…
  19. 深度学习之Bottleneck Layer or Bottleneck Features
  20. 【Go语言入门100题】038 新世界 (5 分) Go语言|Golang

热门文章

  1. 朴实无华,25个常用Matplotlib图的Python模板代码
  2. [初级-详细]新大陆NewLand云平台Android离线程序开发(离线导入Moudle)
  3. 世界时钟-国家中英文名称-国家代码-与北京的时差 一览
  4. 【读书笔记】大数据 数据挖掘 相关
  5. 新浪博客服务器是不是在维护,新浪博客是不是又在升级了?
  6. PHPStudy安全配置
  7. java中ant_java ant使用详解
  8. C64x的软件优化方法
  9. 删除可恶的7654.com,7654导航篡改首页恢复,如何解决浏览器被7654劫持
  10. 图片怎么去底色?怎么去图片背景为透明?