您的位置:首页 > 其它

2-1 众数问题

2016-09-19 20:49 253 查看
给定含有n个元素的多重集合S,每个元素在S中出项的次数称为该元素的重数。多重集S中重数最大的元素称为众数。

例如S={1,2,2,2,3,5}。多重集S的众数是2,其重数为3.

算法一:使用C++STL的map容器关键字作为元素,值为出现发的次数

tip:简单遍历一遍时间复杂度为O(nlgn)map插入时间nlgn
#include <iostream>
#include <stdlib.h>
#include <fstream>
#include <map>

using namespace std;

int main()
{
ifstream input("input.txt",ios::in);
ofstream output("output.txt",ios::out);

if (!input)
{
cerr<<"input file could not be opened"<<endl;
exit(1);
}

map<int,int> number_count;

int n;
input>>n;

int data;
while(n--)
{
input>>data;
number_count[data]++;
}

int _max=-1;
auto flag=number_count.begin(),it=number_count.begin();

for(;it!=number_count.end();it++)
{
if(it->second>_max)
{
flag=it;
_max=it->second;
}
}

output<<flag->first<<endl<<flag->second<<endl;

auto rep=++flag;

for(;rep!=number_count.end();rep++)
{
if(rep->second==flag->second)
{
output<<rep->first<<endl<<rep->second<<endl;
}
}

return 0;
}



算法二:

使用数组排序后,找出众数。时间复杂度O(NlogN);

//使用数组记录下所有的数值,经过排序后,两层for循环解出
//时间复杂度O(NlogN)
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 100

int a
;
/*
int partition(int s,int e)
{
int i=s;int j=e+1;
int x=a[s];

while(1)
{
while(a[++i]<x&&x<e);
while(a[--j]>x);

if(i>=j)break;

swap(a[i],a[j]);
}

swap(a[s],a[j]);
return j;
}

void Qsort(int s,int e)
{
if(s<e)
{
int q=partition(s,e);
}

}
*/
int main()
{
FILE *fp1=NULL,*fp2=NULL;
if(!(fp1=fopen("input.txt","r")))
{
printf("input.txt open error!\n");
return 0;
}
if(!(fp2=fopen("output.txt","w")))
{
printf("output.txt open error!\n");
return 0;
}
int n;
while(!feof(fp1))
{
fscanf(fp1,"%d",&n);
for(int i=0;i<n;i++)
fscanf(fp1,"%d",&a[i]);
fgetc(fp1);

//Qsort(0,n-1);
sort(a,a+n);
int _max=1,cnt=1;
for(int i=1;i<n;i++)
{
if(a[i]==a[i-1])		//从第二个数字开始遍历,如果这个数和前面的数相同,则计数+1,否则计数记为1
cnt++;
else
{
_max=max(_max,cnt);
cnt=1;				//更新cnt的值
}
}
_max=max(_max,cnt);		//	//该for循环是将众数输出,众数可能不只有一个

cnt=1;
for(int i=1;i<n;i++)
{
if(a[i]==a[i-1])
cnt++;
else
{
if(cnt==_max)
fprintf(fp2,"%d\n%d\n",a[i-1],_max);
cnt=1;
}
}
if(cnt==_max)
fprintf(fp2,"%d\n%d\n",a[n-1],_max);

}
fclose(fp1);
fclose(fp2);
printf("bingo!\n");
return 0;
}


.

算法三(分治与递归):

– 先根据某数X,将小于X的放于其左,大于X的放于其右
– 统计X出现的次数T
– 如果X左边数的个数>T,向左递归
– 如果X右边数的个数>T,向右递归


时间复杂度分析:



代码:
#include <iostream>
#include <stdlib.h>
#include <fstream>
const int MAX=100;

using namespace std;

int Random(int p, int r){//随机化
//return rand()*(r-p)/32767+p;
return rand()%(r-p)+p;
}

void Swap(int* c, int* d){
int temp;
temp= *c;
*c = *d;
*d = temp;
}

//小于x放置左边,大于x的放置右边
int Partition(int* y, int p, int r){
int i = p, j = r+1;
int x = y[p];
while(true){
while(y[++i]<x&&i<r);
while(y[--j]>x);
if(i>=j) break;
Swap(&y[i],&y[j]);
}
y[p] = y[j];
y[j] = x;
return j;
}

int RandomizedPartition(int* y, int p, int r){
int i = Random(p,r);
Swap(&y[i],&y[p]);
return Partition(y,p,r);
}

void FindModeIndex(int* y,int i,int* left_index,int* right_index)
{
int mode=y[i];
int left=i;
int right=i;
while(y[--left]==mode);
while(y[++right]==mode);
left++;
right--;
//最后一次等于mid的下标,因为已经将小于等于x的放在左侧
//大于等于的放在右侧,所以right-left+1就是x的出现次数;

*left_index=left;
*right_index=right;
}

void FindMode(int* y, int p, int r, int& mode, int& count){
int i = RandomizedPartition(y,p,r);
int left_index;
int right_index;

int count_mid,count_left,count_right;
FindModeIndex(y,i,&left_index,&right_index);
count_mid=right_index-left_index+1;

count_left=left_index-p;

count_right=r-right_index;
if(count_mid>=count)
{
mode=y[i];
count=count_mid;
}

//如果左边数的和大于等于统计的x的重数,左边递归求解;
if(count_left>=count_mid) FindMode(y,p,left_index-1,mode,count);
//如果右边数的和大于等于统计的x的重数,左边递归求解;
if(count_right>=count_mid)  FindMode(y,right_index+1,r,mode,count);
return;
}
int main()
{
ifstream input("input.txt",ios::in);
ofstream output("output.txt",ios::out);

if (!input)
{
cerr<<"input file could not be opened"<<endl;
exit(1);
}

int n;
int mode;
int count;

input>>n;
int a
;

for(int i=0;i<n;i++)
input>>a[i];

mode=MAX;
count=0;

FindMode(a,0,n-1,mode,count);
output<<mode<<endl<<count<<endl;

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: