7.8 *案例:直接选择排序
排序是计算机算法的基础。而直接选择排序是排序一种比较简单的算法。
已知数组这样定义:int 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++,回到第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 。
下面是排序的函数伪代码:
public static void sort(int[]arr){
for(int i=0;i < arr.lenth-1;i++){
找到i到9之间的最小值的下标,赋给m;
互换下标m和下标i的元素;
}
}
这个是根据上面的算法得来的,其中第4行代码minIndex(arr[10],i)函数的功能是:从下标i开始查找数组的最小值,返回最小值的下标。
特别注意,我们要找的是下标!为什么呢?因为知道下标才能互换数组里面的元素。想象直接找最小值的情形:找到最小值3,和第一个元素互换,第一个元素可以赋值为3,然而第一个元素原来的值(例如是24)又要赋给谁呢?应该赋给3这个元素原本的位置,但是,我们根本不知道3这个元素在哪个位置!如果是找最小值的下标,那么互换就是轻而易举的事情了。
综合第3到8行代码就是:第i个元素和i后面所有的元素比较,找到最小的那个数,和第i个元素互换。也就是第(2)步。
实现sort函数还需要实现minIndex和exchange函数。到这一步的时候就能看出函数的作用了:即使关键问题没有解决,仍然可以把函数的框架写出来。当然你需要清楚未解决的问题,需要什么参数,返回什么值。
我们先来解决了这个最小值的问题。
查找数组里的最小值,在之前的练习出现过(求数组最小值)。
它的算法是:
1.最小值m初始化为第一个元素。
2.i=1,把m和arr[i]之间较小的数赋给i
3.i加1,没有越界的话回到第2步。
Math.min返回两个参数中小的那个数字,是Java内置的函数。
现在稍微修改这个算法,把最后返回的最小值,变成返回返回最小值的下标。
至于exchange函数,可以参考上一节最后一题