1.设计思想
首先利用快排的partition进行划分,在分区的同时统计与pivot相等的元素的个数n(重数),如果n都大于pivot左右两边元素的个数,那它就是众数,否则选取比n大或等的分区采用同样的方法进行递归,并与原来的pivot和它的重数进行比较,选取大的,当递归结束后,众数以及它的重数就出来了。
2.c++实现
/*
程序:求数组众数
作者:Moyu
*/
#include<iostream>
#include<vector>
using namespace std;
/*
函数:一次划分
参数:A:数组 lo:下限 hi:上限 n的引用:轴值出现的次数
返回值:轴值的位置
*/
int Partition(vector<int> &A, int lo, int hi, int &n)
{
n = 0;
int pivot = A[lo];
while(lo < hi){
while(lo < hi && A[hi] >= pivot){
if(A[hi] == pivot)
++n;
--hi;
}
A[lo] = A[hi];
while(lo < hi && A[lo] <= pivot){
if(A[lo] == pivot)
++n;
++lo;
}
A[hi] = A[lo];
}
A[lo] = pivot;
++n;
return lo;
}
/*
函数:求数组的众数
参数: A:数组 lo:下限 hi:上限 v:数组众数集合 n的引用:众数出现的次数
*/
void GetMode(vector<int> &A, int lo, int hi, vector<int> &v, int &n)
{
//一次划分,并求轴值出现的次数
int num = 0;
int m = Partition(A,lo,hi,num);
//对左半部分求数组众数
vector<int> vl;
int numl = 0;
if(num <= m - lo)
GetMode(A,lo,m-1,vl,numl);
//对右半部分求数组众数
vector<int> vr;
int numr = 0;
if(num <= hi - m)
GetMode(A,m+1,hi,vr,numr);
//整合
if(num >= numl && num >= numr){
n = num;
if(num == numl)
v.insert(v.end(),vl.begin(),vl.end());
if(num == numr)
v.insert(v.end(),vr.begin(),vr.end());
v.push_back(A[m]);
}
else if(numl >= num && numl >= numr){
n = numl;
if(numl == num)
v.push_back(A[m]);
if(numl == numr)
v.insert(v.end(),vr.begin(),vr.end());
v.insert(v.end(),vl.begin(),vl.end());
}
else if(numr >= num && numr >= numl){
n = numr;
if(numr == numl)
v.insert(v.end(),vl.begin(),vl.end());
if(numr == num)
v.push_back(A[m]);
v.insert(v.end(),vr.begin(),vr.end());
}
}
int main()
{
vector<int> A = {1, 4, 2, 9, 8, 11, 16, 6, 7, 7};
cout << "数组:";
for(auto i : A)
cout << i << " ";
cout << endl;
vector<int> v;
int n;
GetMode(A,0,A.size()-1,v,n);
if(v.size() == A.size())//若所有值皆为众数,则无众数
cout << "不存在众数!!!" << endl;
else{
cout << "众数:";
for(auto i : v)
cout << i<< " ";
cout << endl;
cout << "重复次数:";
cout << n << endl;
}
return 0;
}
3.结果与总结
运行截图
箴言录:
合抱之木,生于毫末;九层之台,起于垒土;千里之行,始于足下。