vlambda博客
学习文章列表

选择排序,你真的明白了吗?

大家有没有类似的感觉?无论是面试还是笔试,提起选择排序大家都觉得很简单,但是再具体写代码的时候会出现各种各样的问题:

比如,外层循环的边界条件总是写错;内存循环中无序区间的长度是不断变化的,如何准确控制?
本文就来给大家解决这些痛点,并且让大家过目不忘。( 代码是java写的)
一,选择排序的思想:

把待排序的数组划分成有序区间和无序区间,从无序区间中找到最大的数,放到无序区间的最后一位;

进行多轮以上操作,直到整个数组有序。
二,具体如何操做?以array数组为例进行讲解:
划分有序区间和无序区间,开始无序区间的数组长度为整个数组的长度array.length,无序区间的数组长度为0。
对整个无序区间进行以下操作:
(1)max=0,指向无序区间第一个数,j=1,指向无序区间第二个数

(2)比较j和max指向的数,如果max指向的数小于j指向的数,则max=j;j不断右移,进行比较操作,直到无序区间最后一个数,最后结果如下:

选择排序,你真的明白了吗?

(3)交换max指向的数据和无序区间的最后一个数,结果如下:

此时整个无序区间中最大的数到了无序区间的最后一位无序区间的长度减少1,有序区间的长度增加1;
不断循环进行以上操作,直到整个数组有序,并且在整个循环当中,每循环一次无序区间的长度减1,有序区间的长度加1
那么问题来了,要循环多少次以上操作?并且无序区间的长度是动态变化的,如何去控制;
循环好写,但是边界条件不好定,这也是为什么我们在LeetCode上每次写题,思路貌似很清晰,代码也感觉很好写,但是写完已提交,总是无法通过,归根结底,没有解决痛点。
三,核心问题分析
1,要循环多少次以上操作?(决定最外层循环控制次数)
每次循环有序区间和无序区间长度变化如下:

所以总共进行整个数组的长度减1次比较,即array.length-1次。
为什么最后一次无序区间长度为2而不是1? 因为两个数比较一次就可以决定其次序。
外层循环控制代码如下:
for (int i = 0; i < array.length-1 ; i++){}
2,无序区间的长度是动态变化的,如何去控制?

i为控制最外层循环的变量,从0开始。j为内层无序区间下标控制变量,从1开始(为什么从1开始,上文有讲解)。每循环一次i增加1,而无序区间的长度就减少1,可用array.length-i进行控制,控制内层循环代码如下:

for (int j = 1; j <array.length-i ; j++){}
这样就能动态表示外层每循环一次,无序区间长度的变化过程,从array.length,array.length-1,......直到2;
到现在为止分析完了,选择排序的核心代码如下:
public void selectSort(int[] array){ for (int i = 0; i < array.length-1 ; i++) { int max=0; for (int j = 1; j <array.length-i ; j++) { if(array[max]<array[j]){ max=j; } } int temp=array[max]; array[max]=array[array.length-i-1]; array[array.length-i-1]=temp; } }
四,时空复杂度
选择排序的时间复杂度为O(n*n),空间复杂度为O(1)。

彩蛋~~~
如果还有不清楚的地方, 欢迎大家关注B站,码农一饭,有视频讲解哦
另外,讲 选择排序是为后面讲堆排序做铺垫。