题目如下:
分治法求众数:
给定含有n个元素的多重集合S,每个元素在S中出现的次数称为该元素的重数。多重集S中重数最大的元素称为
众数。例如,S={1,2,2,2,3,5}。多重集S的众数是2,其重数为3。
编程任务:对于给定的由n个自然数组成的多重集S,采用分治算法编程计算S的众数及其重数。
输入格式
第1行多重集S中元素个数n;接下来的一行为集合S,有n个自然数。( n < 1000000 )
输出格式
结果输出:输出2个数,第1个数为众数,第2个为其重数。
当有多个同样重数的众数,优先输出数值更小的数的众数。
输入样例
6
1 2 2 2 3 5
输出样例
2 3
这个题目可以做的方法挺多,但是它要求要用分治法来求解。
思路分析:
1. 先排序
至于排序的算法,我这里直接使用C++里面提供的函数:
sort(vector.begin(), vector.end());
在后续的博文再总结一下排序算法的问题
2. 找中位数与其个数
这一步是最关键的,基本上这个写出来,程序已经算是完成8成了。
以中位数为起点,向两边比较得出中位数的个数,并记录中位数到两边的位置。
这里会定义几个数:
int number;//输入的个数
int largest = 0;//最大的数
int lar_number = 0;//最大的数的个数
//上面几个是全局变量
int l, ll, r, rr;
//l表示最左边,ll表示左边的最右边。r表示右边的最左边,rr表示右边的最右边
//这几个表示求出中位数之后得出的边界,以便下一次的递归。
3.分治递归
在第二步的基础上,我们采用递归方式:
void solve(vector<int> array, int s, int e, int flag)
//这里s表示start起点,e表示end终点,flag用来表示这个递归是在左边还是在右边,因为我们
//可能会遇到右边的中间数刚好跟左边的一样,这个时候只能取左边的。
下面是具体代码:(代码的本质有点重复了,显得比较臃肿,还可以多加改进,希望大家多多交流)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int number;//输入的个数
int largest = 0;//最大的数
int lar_number = 0;//最大的数的个数
void solve(vector<int> array, int s, int e, int flag) {
if ((e - s) + 1 >= lar_number) {
int mid_value = array[(s + e) / 2];
int l = 0, ll = (s + e) / 2 - 1, r = (s + e) / 2 + 1, rr = e;
//接下来定义中位数的个数
int mid_number = 1;
//这里算最左边的
for (int i = ll; i >= 0; i--) {
if (array[i] == mid_value) {
//mll减一,mid_nuber加一
ll--;
mid_number++;
}
else
break;
}
//现在算最右边的:
for (int i = r; i <= rr; i++) {
if (array[i] == mid_value) {
//r加一,lar_number也加一
r++;
mid_number++;
}
else
break;
}
if (mid_number > lar_number) {
largest = mid_value;
lar_number = mid_number;
}
else {
if (mid_number == lar_number) {
if (flag == 1) { //等于1则是左边的,要不然就不用等于了
largest = mid_value;
lar_number = mid_number;
}
}
}
solve(array, l, ll, 1);
solve(array, r, rr, -1);
}
else {
return;
}
}
int main() {
cin >> number;
vector<int> array(number);
int in;
for (int i = 0; i < number; i++) {
cin >> in;
array[i] = in;
}
sort(array.begin(), array.end());
int l, ll, r, rr;
//l表示最左边,ll表示左边的最右边。r表示右边的最左边,rr表示右边的最右边
l = 0;
ll = number / 2 - 1;
r = number / 2 + 1;
rr = number - 1;
//初定义largest为中位数, lar_number为1
largest = array[number / 2];
lar_number = 1;
//这里算最左边的
for (int i = ll; i >= 0; i--) {
if (array[i] == largest) {
//ll减一,lar_number加一
ll--;
lar_number++;
}
else
break;
}
//现在算最右边的:
for (int i = r; i <= rr; i++) {
if (array[i] == largest) {
//r加一,lar_number也加一
r++;
lar_number++;
}
else
break;
}
solve(array, l, ll, 1);
solve(array, r, rr, -1);
cout << largest <<" " << lar_number;
return 0;
}