问题:当给定存在静态表(如数组)中的n个元素,如何快速找到其中位数、最小值、最大值、第i小的数?
首先想到的方法是先对数组元素进行排序,然后找到第i小的元素。这样是可行的,但比较排序最快也需要O(nlgn),能否在线性时间内解决呢。这就是随机的分治法—随机选择。
思想:利用随机划分(在快速排序中介绍过)找到主元r,这样就将小于等于r的元素放在了其左边,大于r的元素放在了其右边。这是可以计算出r的rank为k,如果正好等于i,则就返回该元素;如果k大于i,则在左边中寻找第i小的元素,否则在右边中寻找第i-k小的元素。
#include <iostream> #include <ctime> using namespace std; void swap(int &t1, int &t2){ int tmp = t1; t1 = t2; t2 = tmp; } int randomPartition(int r1[], int p, int q){ srand((unsigned)time(0)); int randInt = rand()%(q-p+1)+p; // 随机选择一个元素作为主元 swap(r1[p], r1[randInt]); int i = p, j = p+1; int pivot = r1[p]; for(j = p+1; j <= q; j++){ if(r1[j] < pivot){ i++; swap(r1[i], r1[j]); } } swap(r1[i], r1[p]); return i; } // 随机选择算法 找到n elements, the kth smallest element int randomSelect(int r1[], int p, int q, int i){ if(p == q) return r1[p]; int r = randomPartition(r1, p, q); int k = r - p + 1; // 划分r1[r]左边元素个数 包括r1[r] if(i == k) return r1[r]; if(i < k) return randomSelect(r1, p, r-1, i); // 在左边寻找第i小元素 else return randomSelect(r1, r+1, q, i-k); // 在右边寻找第i-k小元素 } int main(){ int a[10] = {3,10,2,2,7,8,4,8,8,19}; for(int i = 1; i <= 10; i++){ cout << randomSelect(a, 0 ,9, i) << endl; } return 0; }
将排名前10的结果都输出来了
通过分析可以得出该算法的时间复杂度为O(n),当然最坏的情况为O(n^2).
原文地址:http://blog.csdn.net/lu597203933/article/details/43418179