在前一篇讲选择数问题时,使用了一种类似于快速排序的算法来解决选择数问题,见:http://www.iflym.com/index.php/code/201108240001.html。
而根据算法导论上的一种最坏时间为O(n)的一种解法,其详细的步骤如下所示:
- 将数组s按5个为一组,划分成不同的小组,小组数
- 对每个小组,进行插入排序,并选择其中的中位数
- 将每个小组的中位数,组成一个新的数组,并递归的选择出最终的中位数m
- 以m作为参照数,将数组s划分成两个部分,使得m所处的位置数比左侧的数目大1
- 如果左侧的数目数恰好为寻找的第k位数,则m即为我们要找的数,否则继续在左侧或者右侧进行查找
有了几个的思路,具体算法就很简单了。参考代码如下所示:
private static int find2(int[] ints, int k, int start, int end) { //如果k为1,则寻找最小数,如果k为end-start+1则寻找最大数 //总长度小于5,直接插入排序并查找 ...... //寻找到中位数 int z = findMiddle(ints, start, end); //按中位数分割数组,其中ints[divide]=z int divide = divide(ints, z, start, end); //判断在哪个部分 int frontNum = divide - start; //恰好为中位数 if(frontNum == k - 1) return ints[divide]; //高部分 if(frontNum < k) return find2(ints, (k - frontNum), divide + 1, end); //低部分 return find2(ints, k, start, divide - 1); }