选择排序是怎么做的

Posted 南北技术笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了选择排序是怎么做的相关的知识,希望对你有一定的参考价值。

周日在家比较无聊,感冒依然没好,心情很差,勉强写一篇简单的选择排序。






1.算法描述:

    选择排序是一种基础排序算法,先定义一个预定元素一般是选择数组中的第一个(你高兴也可以选择最后一个)无序元素作为数组的最大元素),从剩余的未排序的无序元素中,和这个预定元素进行比较,如果大于这个预定元素的话,将最大元素从预定元素切换到这个元素。继续与后面的无序元素做比较,直到比较到最后一个元素,得到整个无序数组的最大元素,交换到预定元素位置上。(在整个过程中,预定元素的位置是变动的)。


2.思路

  1. 设定待排序数组arr。

  2. 首先设定待排序数组的第一个元素是最大元素,设定tmp为最大元素的下标。

  3. 比较预定元素下标tmp对应的值和下一个元素值a2,如果a2>arr[tmp],j将a2的下标赋值给tmp,此时最大元素下标已经改变了。

  4. .....

  5. 比较到最后一个元素,得到第一次排序的最大值对应的下标,比较第二部预定的最大元素下标和第一次排序后得到的最大元素下标进行比较,不一致的话,交换两个元素。(这样每次排序,其实只做一次元素交换)。此时第一个元素已经是有序的了。

  6. 重复2345步骤,直到数组完全有序。


    选择排序逻辑上来说,也是将数组分成了两部分(无序和有序),最开始认为都是无序的,此时排序选择一个元素作为最大元素,然后与其他元素作为比较,直到得到整个无序数组的最大元素。

    和冒泡排序一样,每次排序之后,无序部分元素总数-1,有序部分+1,所以越往后排序,越需要比较的次数就越少。

    和冒泡排序 不同的是,冒泡排序,每次比较都可能发生数据交换,选择排序则是每次比较,只可能修改最大元素的下标,而不是发生数据交换。排序完成之后比较最大下标与预定的下标是否一致才可能发生一次数据交换,从数据交换的角度上来说,需要执行的步数是比冒泡排序要少的。


3.举例

要排序数组:[1,9,10,8,-4]

  • 第一趟排序(总共进行了四次比较,结果[10,9,1,8,-4]),设定最大元素下标为0

    • 第一次比较:1和9比较,9大于1,最大下标修改为1。

    • 第二次比较:9和10比较,10大于9,最大下标修改为2。

    • 第三次比较:10和8比较,8小于10,最大下标不变

    • 第四次比较:10和-4比较,-4小于10,最大下标不变

    • 将最大下标的值与预设下标为0的数据,交换数据。

  • 第二趟排序(进行三次比较,结果[10,9,1,8,-4],第一趟排序已经得到整个无序数组的最大值,所以数组前的第一个元素已经是有序的了,设定最大元素下标是无序数组的第一个元素,下标应该是1)

    • 第一次比较:9和1比较,1小于9最大下标不变

    • 第二次比较:9和8比较,8小于9,最大下标不变

    • 第三次比较:9和-4比较,-4小于9,最大下标不变

  • 第三趟排序(进行两次比较,得到[10,9,8,1,-4],此时预设下标为2)

    • 第一次比较:1和8比较,8大于1,修改下标为3

    • 第二次比较:-4和8比较,-4小于8,最大下标不变。

    • 将最大下标的值与预设下标为2的数据,交换数据。

  • 第四趟排序(进行一次比较,得到[10,9,8,1,-4])

    • 第一次比较:-4和1比较,-4小于1,最大下标不变。

    • 至此,排序结束,得到完全有序的数组[10,9,8,1,-4]


4.算法分析

    从上面排序流程,可以看到,对于一个包含N个元素的无序数组,总共需要进行N-1趟排序,假设每趟排序的参数为i,则每趟的比较次数为N-i,所以对于快速排序算法,可以通过双重循环来实现,外层循环控制需要排序的次数,内层循环控制预定最大元素与剩下的无序元素做比较。


5.算法实现

<?php$arr = [1, 9, 10, 8, -4];$length = count($arr);
for ($i = 0; $i < $length; $i++) { $max = $i; for ($j = $i + 1; $j < $length; $j++) { if ($arr[$j] > $arr[$max]) { $max = $j; } }
if ($max != $i) { $temp = $arr[$max]; $arr[$max] = $arr[$i]; $arr[$i] = $temp; }}print_r($arr);


6.选择排序的优点

    选择排序都会得到一个无序数组中最大(或最小)的元素,也可以理解冒泡排序将整个数组分成两个部分,无序和有序两部分,每次排序都会往有序的部分加入一个元素,无序的部分减少一个元素;所以冒泡排序越是执行到后面,需要比较的无序元素就越少,一定程度上减少了算法的量

    选择排序和冒泡排序不同的是,冒泡排序在比较的同时就可能会发生交换操作,而对于选择排序来说,在比较的时候,发现顺序有问题的话,只是会修改预设最大/最小元素的下标,对于一个n个元素的无序数组来说,选择排序最多只需要交换n-1次就可以得到争取的顺序。


7.时间复杂度推算

    我们以最坏的角度来推算,一个n个元素的数组,最多需要n-1次交换,他的比较次数为:C(max) = 1+2+3+...+(N-1)=(n-1)*(n-1+1)/2。

   总步数为:C(max)+n-1。

    对于时间复杂度来说,由最高项的情况下,我们只取最高项,所以冒泡排序的最差时间复杂度为O(n²)。

    



以上是关于选择排序是怎么做的的主要内容,如果未能解决你的问题,请参考以下文章

看动画学算法之:排序-选择排序

编一个C++程序 创建一个选择排序法的函数模板sort 并在main()执行

文件怎么设置手动排序?

与另一个片段通信的片段接口

直接选择排序到堆排序做的那些改进

选择选项卡片段时触发啥事件