SWUST OJ 《选择问题(0445)》题解

题目描述:http://acm.swust.edu.cn/problem/445/

#include<stdio.h>

int num[10002];

//交换脚标为lv和脚标为rv的元素的位置
void Swap(int lv, int rv)
{
	int t = num[lv];
	num[lv] = num[rv];
	num[rv] = t;
}

//找到[left,right)区间中,num[left]的位置
//让num[left]这个数的左边都是比它小的数,右边都是比它大的数
int Partition(int left, int right)
{
	int i = left + 1;
	int j = right - 1;
	while (i <= j)
	{
		while (i <= j && num[j] >= num[left]) j--;
		while (i <= j && num[i] < num[left]) i++;
		if (i < j) Swap(i, j);
	}
	Swap(left, i - 1);
	return i - 1;
}

//对num数组的区间[left,right)的数进行排序
int sort(int left, int right)
{
	for (int i = left; i < right - 1; i++)
	{
		int min = i;
		for (int j = i + 1; j < right; j++)
		{
			if (num[j] < num[min]) min = j;
		}
		Swap(min, i);
	}

	return (right + left) / 2;
}

//找到num数组中区间[left,right)的中位数
int FindMid(int left, int right)
{

	if (left + 5 >= right)
	{
		return sort(left, right);
	}

	int time = (right - left) / 5;
	for (int i = 0; i < time; i++)
	{
		int tmp = sort(left + i * 5, left + i * 5 + 5);
		Swap(left + i, tmp);
	}
	return FindMid(left, left + time);
}

//在区间[left,rught)中,找num数组中的第k大的数
int Find(int left, int right, int k)
{
	int midNum = FindMid(left, right);
	Swap(left, midNum);

	int tk = Partition(left, right);
	if (tk + 1 == k) return num[tk];
	if (tk + 1 > k) return Find(left, tk, k);
	else return Find(tk + 1, right, k);
}

int main()
{
	int n, k;
	while (scanf("%d%d", &n, &k) != EOF)
	{

		for (int i = 0; i < n; i++)
		{
			scanf("%d", &num[i]);
		}

		int ans = Find(0, n, k);
		printf("%d\n", ans);
	}

	return 0;
}


你可能感兴趣的:(C++,代码)