使用C++实现随机选择算法

随机选择算法:从数组中返回第K大的数,并且将数组划分为两个区间,前K-1个数小于K,后n-K个数大于K(n为数组元素)。

这种算法优越的地方就是不需要对数组的所有元素进行排序,就可以找到数组中第K大的数字。

以下是代码实现:

#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 
#include 
#include 
using namespace std;

// 选取随机主元,对区间[left, right]进行划分
int randPartition(vector<int>& v, int left, int right)
{
	// 合法性判断
	if (left >= right || v.size() < right) return -1;

	int p = round(1.0 * rand()) / RAND_MAX * (right - left) + left;
	swap(v[p], v[left]);

	int temp = v[left];	// 主元
	while (left < right)
	{
		// 将right左移,直到某个元素不再大于temp
		while (left < right && v[right] > temp) --right;
		v[left] = v[right];

		// 将left右移,直到某个元素不再小于等于temp
		while (left < right && v[left] <= temp) ++left;
		v[right] = v[left];
	}

	v[left] = temp; // 将temp放到left和right相遇的地方
	return left;
}

// 随机选择算法,从数组中找到第K大的数,并对数组进行切分
void randSelect(vector<int>& v, int left, int right, int K)
{
	if (left == right) return;

	int p = randPartition(v, left, right);	// 划分主元后的位置p
	int M = p - left + 1;	// A[p]是[left,right]中的第M大的数

	if (K == M) return;	// 找到第K大的数
	if (K < M)
	{
		randSelect(v, left, p - 1, K);	// 继续向左边找第 K 大的数
	}
	else
	{
		randSelect(v, p + 1, right, K - M);	// 继续向右边找第 K-M 大的数
	}
}

int main()
{
	srand((unsigned)time(NULL));	// 随机数种子
	int sum = 0, sum1 = 0, n;
	scanf("%d", &n);
	
	vector<int> v(n, 0);
	for (int i = 0; i < n; ++i)
	{
		scanf("%d", &v[i]);
		sum += v[i];	// 统计所有整数之和
	}

	randSelect(v, 0, n - 1, n / 2);	// 找到第n/2大的数,并对数组进行切分
	for (int i = 0; i < n / 2; ++i)
	{
		sum1 += v[i];	// 统计划分区间后,数组的前n/2个数的和
	}

	// sum - sum1 = 较大集合中数组元素的和
	printf("%d\n", (sum - sum1) - sum1);
	return 0;
}

参考《算法笔记》

谢谢阅读

你可能感兴趣的:(算法,算法,数据结构,c++)