数组的众数问题分治解法

★问题描述:

  • 给定含有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.txtinput.txt
62
13
2
2
2
3
5



为了解决这个问题,首先要知道什么叫分治,即分而治之,将一个大问题分解成若干个小问题,那么这个题目怎么用分治来解决呢:

  1. 首先将数据引入数组,并使之变成有序的(这里推荐用快速排序)
  2. 取数组的中位数,寻找中位数的上下限的数组下标(因为数组是有序的,重复的数据可能会有若干个)
  3. 用打擂台的思想,开辟一个结构体,用来存放众数和重数,默认重数为0,当目前的中位数上下限之差加1(植树问题)大于重数时,更新数据,继续递归打擂台
  4. 这里强调一下递归终止条件,当目前的中位数的下限减去使得数组有意义的最小下标,这个值如果小于目前已知的重数,就没有递归下去的意义,于是递归终止,否则就继续向两边递归下去


上代码

#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();
}

经验证,数据结果无误

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值