5.10 *案例:直接选择排序

排序是计算机算法的基础。而直接选择排序是排序一种比较简单的算法。
已知列表:a =[23 , 14 , 56 , 1 , 35 , 89 , 99 , 65 , 73 , 44] ,经过计算,使得列表按照从小到大排序,也就是变成:[1 , 14 , 23 , 35 ,44 , 56 , 65 , 73 , 89 , 99]。
我们来回顾一下直接选择排序的算法:
1.i=0,len=a的长度;
2.如果i小于len,进入3,否则算法结束;
3.找到从i开始到列表末尾(也就是下标为len-1的元素)的最小值的下标k;
4.将这个最小值和i互换,也就是a[i]和a[k]互换;
5,i加1,回到第2步;

以下是算法应用在上面列表的具体演示。
下图是原列表,准备开始循环,带下划线的值是i为下标所在的值,也是可能会和别的值互换的值:
第一轮循环,从i(i为0)开始到列表末尾,找到这里面最小的数字,然后和下标0的元素互换,这样下标为0的元素就是最小的。 这里找到的值是下标为3的值1,互换后如下(灰色底表示两者已经互换过),同时i的值增加1,第一次循环结束:
第二轮循环,从i(i=1)开始到列表末尾(此时i为1,也就是从14开始一直到列表末尾),找到这里面最小的数字,然后和下标为i的元素互换。这次循环没有移动元素,14就是这里最小的数字,同时i的值增加1,第二轮循环结束:
第三轮循环,从i(i=2)开始到列表末尾,找到这里最小的元素然后和下标为i的元素互换。 循环结束后如下图:
第四轮循环,从i(i=3)开始到列表末尾,找到这里最小的元素然后和下标为i的元素互换。 循环结束后如下图:
第五轮循环,从i(i=4)开始到列表末尾,找到这里最小的元素然后和下标为i的元素互换。 循环结束后如下图:
第六轮循环,从i(i=5)开始到列表末尾,找到这里最小的元素然后和下标为i的元素互换。 循环结束后如下图:
第七轮循环,从i(i=6)开始到列表末尾,找到这里最小的元素然后和下标为i的元素互换。 循环结束后如下图:
第八轮循环,从i(i=7)开始到列表末尾,找到这里最小的元素然后和下标为i的元素互换。 循环结束后如下图:
第九轮循环,从i(i=8)开始到列表末尾,找到这里最小的元素然后和下标为i的元素互换。 循环结束后如下图:
最后一轮循环发现,列表的最后一个元素不需要再计算了,它肯定是最大的元素。也就是循环次数是列表的长度减1.
抽象地概括,就是:第n次循环,将找到第n+1小的元素然后和下标为n的元素互换(n从0开始)。 等到循环结束,也就是n等于列表长度减1的时候,整个列表就是从小到大排好序的。
现在我们用函数来分解这个题目。排序最关键的是第(3)步——找到从i开始到列表末尾的最小值的下标k 。 下面是排序的函数伪代码:
def sort(arr):
    for i in range(len(arr)):
        从i开始找到最小值的下标,赋给m  
        互换列表arr下标m和下标i的元素,也就是arr[m]和arr[i]互换
这个是根据上面的算法得来的,其中第4行代码minIndex(arr[10],i)函数的功能是:从下标i开始查找列表的最小值,返回最小值的下标。
特别注意,我们要找的是下标而不是最小值!为什么呢?因为知道下标才能互换列表里面的元素。想象直接找最小值的情形:找到最小值3,和第一个元素互换,第一个元素可以赋值为3,然而第一个元素原来的值(例如是24)又要赋给谁呢?应该赋给3这个元素原本的位置,但是,我们根本不知道3这个元素在哪个位置!如果是找最小值的下标,那么互换就是轻而易举的事情了。
综合第3到6行代码就是:从第i个元素开始,找到最小的那个数,和第i个元素互换。也就是第(2)步。
实现sort函数还需要实现minIndex和exchange函数。到这一步的时候就能看出函数的作用了:即使关键问题没有解决,仍然可以把函数的框架写出来。当然你需要清楚未解决的问题,需要什么参数,返回什么值。
我们先来解决了这个最小值的问题。
查找列表里的最小值,在之前的练习出现过4.2 遍历(查找列表的最小值)。 它的算法是:
1.最小值m初始化为第一个元素。
2.i=1,把m和arr[i]之间较小的数赋给i
3.i加1,没有越界的话回到第2步,否则m就是最小值。
现在稍微修改这个算法,把最后返回的最小值,变成返回最小值的下标。

至于exchange函数,可以参考上一节最后一题5.5 遍历swap函数