众数问题(递归分治)
问题描述:
给定含有n个元素的多重集合s,每个元素在S中出现的次数称为该元素的重数。多重集S中重数最大的元素称为众数。例如, S-(1, 2, 2, 2, 3, 3, 5).多重集S的众数是2,其重数为3,对于给定的由n个自然数组成的多重集s,计算S的众数及其重数。如果出现多个众数,请输出最小的那个。
输入数据的第1行是多重集S中元素个数n (n<1 300000) ;接下来的n行中,每行有一个最多含有5位数字的自然数。输出数据的第1行给出众数,第2行是重数。
样例为:
Sample input
6
1
2
2
2
3
5
Sample output
2
3
算法思想:
-
取中位数的个数为重数,中位数为众数,确定左界、右界。
-
在往左界递归取中位数为众数,个数为重数,比较
-
往右界递归取中位数为众数,个数为重数,比较
注意!!! -
如果中位数的个数大于左界个数,那左边一定没有该组数据的众数;反之,右边一样。
-
该程序要求数据有序(从小到大),本程序未写排序算法。
#include "stdio.h"
#include "stdlib.h"
# define N 100
void Split(int a[],int n,int &l,int &r)
{//以中间数字为界,确定左右界
int mid = n/2;
for(l = 0;l <= mid;++l)//找左界
if(a[l] == a[mid])
break;//此时l为左界
for(r = mid + 1;r < n;++r)//找右界
if(a[r] !=a[mid])
break;//此时r为右界
}
void getMaxNum(int &num,int &maxnum,int a[],int n)
{//求众数和重数
int l,r,s;
int mid = n/2;
Split(a,n,l,r);
s = r - l;
if(s > maxnum)
{//如果中间数字的个数大于现在的重数,则更新
num = a[mid];
maxnum = s;
}
if(s == maxnum)//如果出现多个众数,输出最小的那个
if(num > a[mid])
{
num = a[mid];
maxnum = s;
}
if(l+1 > maxnum)
//如果左边的个数>maxnum,则搜索左边
getMaxNum(num,maxnum,a,l+1);
if(n - r > maxnum)
//如果右边的个数>maxnum,则搜索右边
getMaxNum(num,maxnum,a+r,n-r);
}
int main()
{
int i,n,a[N];
int num = 0;//num为众数
int maxnum = 0;//maxnum为重数
scanf("%d",&n);//输入数据个数
for(i = 0;i < n;i++)
scanf("%d",&a[i]);//输入数据
//sort(a[i]);//将数据排序
getMaxNum(num,maxnum,a,n);
printf("%d\n%d",num,maxnum);
return 0;
}
运算结果为: