★问题描述:
- 给定含有n个元素的多重集合S,每个元素在S中出现的次数称为该元素的重数。多重集S中重数最大的元素称为众数。
例如,S={1,2,2,2,3,5}。 多重集S的众数是2,其重数为3
★编程任务:
- 对于给定的由n个自然数组成的多重集S,编程计算S的众数及其重数。
★数据输入:
- 输入数据由文件名为input.txt的文本文件提供。文件的第1行多重集S中元素个数n;接下来的n行中,每行有一个自然数。
★结果输出:
- 程序运行结束时,将计算结果输出到文件output.txt中。输出文件有2行,第1行给出众数,第2行是重数。
输入文件示例 | 输出文件示例 |
---|---|
input.txt | input.txt |
6 | 2 |
1 | 3 |
2 | |
2 | |
2 | |
3 | |
5 |
为了解决这个问题,首先要知道什么叫分治,即分而治之,将一个大问题分解成若干个小问题,那么这个题目怎么用分治来解决呢:
- 首先将数据引入数组,并使之变成有序的(这里推荐用快速排序)
- 取数组的中位数,寻找中位数的上下限的数组下标(因为数组是有序的,重复的数据可能会有若干个)
- 用打擂台的思想,开辟一个结构体,用来存放众数和重数,默认重数为0,当目前的中位数上下限之差加1(植树问题)大于重数时,更新数据,继续递归打擂台
- 这里强调一下递归终止条件,当目前的中位数的下限减去使得数组有意义的最小下标,这个值如果小于目前已知的重数,就没有递归下去的意义,于是递归终止,否则就继续向两边递归下去
上代码
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
typedef struct
{
int Num;//众数
int N;//重数
}Node;//存众数的结构体
Node D;//来个全局变量
typedef struct
{
int low;//中位数最早出现的下标
int high;//中位数最后出现的下标
int D;//中位数的值(Data)
}Mid;
int DataIn(int a[])
{
//引入数据
FILE* fp;
if ((fp = fopen("input.txt", "r")) == NULL)
cout << "ERROR"; EOF;
int n;//用来表示多重集里有多少元素
fscanf(fp, "%d", &n);//读取第一行
for(int i=1;i<=n;i++)//注意这里从数组第一格开始,便于后续操作
fscanf(fp, "%d", &a[i]);
fclose(fp);//数据引入结束,关闭文件
return n;
}
void QuickSort(int Data[],int low,int high)//快速排序
{
if (low < high)
{
int i = low, j = high,key=Data[i];
while (i < j)
{
while (i < j && Data[j] <= key)
j--;
if (i<j && Data[j]>key)
Data[i] = Data[j];
while (i < j && Data[i] >= key)
i++;
if (i < j && Data[i] < key)
Data[j] = Data[i];
Data[i] = key;//基准数归位
QuickSort(Data, low, i - 1);//向左递归
QuickSort(Data, i + 1, high);//向右递归
}
}
}
void SearchData(int Data[],int low,int high)//寻找众数及其重数
{
if (low != high)
{
int mid = low + high / 2;
Mid Num;//存放中位数信息
Num.D = Data[mid];
Num.high = Num.low = mid;//默认中位数的上下限为0
while (Data[Num.low - 1] == Num.D)//寻找下限
Num.low--;
while (Data[Num.high + 1] == Num.D)//寻找上限
Num.high++;
if ((Num.high - Num.low+1) > D.N)
{
D.N = Num.high - Num.low+1;
D.Num = Num.D;
}
if ((Num.low - low) > D.N)//如果左边递归的数据总数小于重数就没递归的必要
SearchData(Data, low, Num.low - 1);
if ((high - Num.high) > D.N)//同理
SearchData(Data, Num.high + 1, high);
}
}
void DataOut()//数据输出
{
FILE* fp;
if ((fp = fopen("output.txt", "w")) == NULL)
cout << "ERROR"; EOF;
fprintf(fp, "%d\n%d", D.Num, D.N);
fclose(fp);
}
int main()
{
int Data[100];//开辟一个存数据的数组
int n;//数据个数
n = DataIn(Data);
QuickSort(Data, 1, n);//进行快速排序(升序)
D.N = 0;//默认众数的重数为0
SearchData(Data, 1, n);
DataOut();
}
经验证,数据结果无误