求主元素:先求出中位数,由于主元素必为中位数,因此只需要判断中位数出现次数是否大于n/2即可。
寻找中位数:用线性方法寻找第k大的数即可在O(n)内找到中位数。
设T[0:n-1]是n个元素的数组。对任一元素x,设S(x)={ i | T[i]=x}。当|S(x)|>n/2时,称x为主元素。设计一个线性时间算法,确定T[0:n-1]是否有一个主元素。
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#define N 100005
using namespace std;
int partition(int a[], int s, int e)
{
int m = (s + e) / 2;
int i = s, j = e;
int pivot = a[s];
while (i < j)
{
while (i < j && a[j] >= pivot)
j--;
swap(a[i], a[j]);
while (i < j &&a[i] <= pivot)
i++;
swap(a[i], a[j]);
}
return i;
}
int search(int a[], int s, int e, int k)
{
if (s == e) return a[s];
else
{
int pivot = partition(a, s, e);
int tmp = pivot - s + 1;//位于枢轴左边的元素个数(包括枢轴)
if (tmp == k)//枢轴正好位于第k大的数的位置
return a[s + k - 1];
if (tmp > k)//从左半边找第k大的数
return search(a, s, pivot - 1, k);
else//从右半面找第k-tmp大的数
return search(a, pivot + 1, e, k - tmp);
}
}
void judge(int a[], int n, int num)
{
int cnt = 0;
for (int i = 0; i < n; i++)
{
if (a[i] == num)
cnt++;
}
if (cnt > n / 2)
printf("主元素为%d\n", num);
else
printf("不存在主元素\n");
}
int main()
{
freopen("e:\\input.txt", "r", stdin);
int a[N];
int n;
while (~scanf("%d", &n))
{
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
int ans = search(a, 0, n-1, n / 2);//ans为中位数
judge(a,n,ans);
}
return 0;
}