摘要(1):当一个元素个数为N的数组中,某个元素出现的次数超过N/2次,就叫这个元素为主元;
(2)现实现一种教科书的算法:{1}:找出一个主元的候选元(难点){2}确定该候选元是否是主元(简单)
首先:对数组A[N]进行遍历,比较A1与A2,如果A1与A2相同,则将A1放入数组B中,否则不进行任何处理。然后比较A3与A4,以相同方式直到遍历整个数组,然后递归的对B进行遍历。最后找出的就是候选元。
(3)分析该算法:首先证明该算法的合理性:{1}为方便起见,设N=2k,如果x是主元,则x至少出现k+1次。
{2}对N进行两两分组设x与自己配对m次,(m显然不可能为0,否则N>2k,这意味着主元一定进入B),则x与其他元素配对k+1-2m次(这些元素都不可能进入B,因为它们与x配对且不是x),则剩下元素(不一定是同一个元素,可以是y,z,w……)最多配对次数为:k+1 - (m+ k+1-2m)= m-1
{3}m>m-1,因此x在B依旧是主元,因此递归的对B进行算法是成立的。(初始情况成立,类似数学归纳法的逻辑).
其次讨论N = 2k + 1时的情况,同样的逻辑分析是适用的,需要注意的是在代码上的处理
(4)对N = 2k+1的代码处理,首先依然对N = 2k进行算法,现在讨论三种情况,第一种没有主元,那么不需要进行多余处理.
第二种有主元x,且x在A[N-1]
(下标从0开始),那么利用(3)的分析可知x在B出现m次,而其余元素可能在`B出现的次数是k-(m+k-2m)= m,注意,x不在是主元了,因此必须要对x进行处理,将最后一个x加入B。
最后一种,x是主元,但都分布在前N-1个,那么与N=2k时一样,不需要处理。
#include "stdafx.h"
#include "stdlib.h"
#define Max_N 15
#define Error -1999
int find(int *A, int N)
{
int b[Max_N];
int j = 0,i = 0;
int num;
if (N==0)
exit(-1);
if (N == 1)
{
if (A[N-1]!= Error)
return (A[N-1]) ;
else
return Error;
}
for (i = 0;i<=N-2;i += 2)
{
if (A[i] == A[i+1])
b[j++] = A[i];
}
if (N%2)//处理N为奇数
{
for ( i=0,num=0;i<=j-1;i++)
if (b[i]==A[N-1]) num++;//考察最后一个元素是不是主元
if (num+1>(j+1)/2) b[j++]=A[N-1];
}
return(find(b,j));
}
int _tmain(int argc, _TCHAR* argv[])
{
int A[Max_N] = {5,5,3,5,6,7,5,3,5,3,1,5,5,2,5};
int s = find(A,Max_N);
int num = 0;
if (s!= Error){
for(int i =0;i<=Max_N-1;i++)
{
if(s == A[i])
num++;
}
if (num>Max_N/2)
printf("the majority is %d",s);
else
printf("nothing");
}
else
printf("nothing");
return 0;
}