在期望线性时间内做出选择
对于求一个数中集合的最大最小值问题可以在线性时间内解决问题,因为对于集合一次扫描就可以做出决定。而如何找出 0 ~ k中的第n大的数呢?可能对于大多数情况来说我们可以对集合进行排序,效率越高越好,再找出第n大的数。这样的时间消耗就是排序的时间消耗。
为了在期望线性时间内做出选择,算法导论中给出了一种随机选择的算法,关于渐进时间为线性的证明书中有。它的思想主要是从随机快速排序算法而来,然而它每次只对快速排序划分的一边进行处理,有点类似二分法(二分快,但其必须是有序的哦)。
过程是对集合进行随机的划分,而对于中枢值来说一次划分就可以找到其正确的位置,我们将中枢值所在位置与要找的n进行对比,如果小于中枢值的位置,就对比中枢值大的部分进行递归随机选择。递归结束的条件是被划分的区间的大小为1,或者中枢值所在的位置就是n。
选择算法之所以有线性的运行时间,是因为它们没有进行排序。
以下是C实现
int getkthnum(int* intarray, int p, int r, int kth) { int q; int k; if(p == r) return intarray[p]; q = randompartion(intarray, p, r); k = q + 1; if (k == kth) return intarray[k - 1]; else { if (k < kth) return getkthnum(intarray, q + 1 , r, kth); else return getkthnum(intarray, p, q - 1, kth); } } int randompartion(int* a, int startpos, int endpos) { assert(startpos < endpos); int size = endpos - startpos + 1; int randompos = 0; //i :first big number j :first undetected number int i, j; int pivot; srand(time(0)); randompos = rand() % size; swap(a, endpos, startpos + randompos); i = startpos; j = startpos; pivot = a[endpos]; while (j != endpos) { if (a[j] < pivot) { swap(a, i, j); i++; j++; } else j++; } swap(a, i, endpos); return i; } void swap(int* a, int pos1, int pos2) { int buffer; buffer = a[pos1]; a[pos1] = a[pos2]; a[pos2] = buffer; } void main() { int len, startpos, endpos; int a[100]; int i; int k; int number; printf("input your number count less than 100 and startposition and end position\n"); scanf("%d%d%d", &len, &startpos, &endpos); printf("input your numbers less than 100....\n"); for (i = 0; i != len; i++) scanf("%d", &a[i]); printf("input the kth number you want to get\n"); scanf("%d", &k); number = getkthnum(a, startpos, endpos, k); printf("the kth number you want to get is %d\n", number); }

浙公网安备 33010602011771号