算法系列笔记2(静态表顺序统计-随机选择算法)

问题:当给定存在静态表(如数组)中的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).

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。