令E是整数x1,x2..xn。E中x的众数是x在E中出现的次数。如果某个数z的众数大于n/2,则它就是众数
问题1:已知一数列,判断是否存在众数,若存在,则求出众数
问题2:对已知的某个有n个元素的列表,找出所有出现超过n/4次的元素。算法设计应该做o(n)次比较
对于问题1,如果规模比较小的话,用桶式排序,时间复杂度为o(n),对于大规模不太实用了。先排序时间复杂度o(n*lgn),排序后,去取第n/2个数,如果有众数的话,比为第n/2的那个数。但时间复杂度有点高,高于o(n)
引理:如果xi!=xj,删除xi,xj ,原来集合的众数时现在集合的众数。否命题不成立,则需要对求出的众数M,进行检验.
思路;假设众数为M,次数为C.如果xi!=M C=C-1;相等的话,则C=C+1; 还有一种情况,C=0的时候要重新选候选M=a[i] C=1;
问题代码如下:
int majority(int a[],int n)//失败为-1 成功返回众数
{
int i;
int C=1;
int M=a[0];
for(i=1;i<n;i++)
{
if(C==0)
{
C=1;
M=a[i];
}else{
if(M==a[i])
{
C=C+1;
}else
{
C--;
}
}
}
int sum=0;
for(i=0;i<n;i++)
{
if(M==a[i]) sum++;
}
if(sum>n/2) return M;
else return -1;
}
对于问题二,修改问题一的众数算法,此时候选为M[3]
代码如下:
int majority_4(int a[],int n)
{
int C[3]={0};
int M[3];
int i,j;
for(i=0;i<3;i++)
M[i]=a[0];
C[0]=1;
for(i=1;i<n;i++)
{
int flag=0;//有C[j]<=0标志为1
int find_flag=0;//找到a[i]==M[j]
for(j=0;j<3;j++)
{
if(C[j]<=0)
{
C[j]=1;
M[j]=a[i];
flag=1;
break;
}else
{
if(M[i]==a[i]) break;
}
}
if(flag==1) continue;
for(j=0;j<3;j++)
{
if(a[i]==M[j])
{
C[j]++;
find_flag=1;
}
}
if(find_flag==1) continue;
for(j=0;j<3;j++)
{
C[j]--;
}
}
int sum[3]={0};
for(i=0;i<n;i++)
{
for(j=0;j<3;j++)
{
if(C[j]>0&&M[j]==a[i])
{
sum[j]++;
break;
}
}
}
int flg=0;
for(j=0;j<3;j++)
{
if(sum[j]>n/4)
{
cout<<" "<<M[j]<<endl;
flg=1;
}
}
if(flg==1) return 1;
else return 0;
}