寻找一个序列中的主元素

http://yilee.info/major-element-algorithm.html

http://www.cnblogs.com/ly772696417/archive/2012/03/22/2410921.html

何谓主元素?具体讲,如果一个数组A[1..n]中超过半数的元素都相同时,该数组被称为含有一个主元素 (a) 设计一个有效算法,确定该数组中是否含有一个主元素,如果有,找出这个元素。(b) 能否给出一个线性时间算法?

注意,该数组的元素之间可能不存在顺序——即不能进行”A[i]<A[j]”的大小判断,但是可以进行是否相等的判断。普通的算法即需要2for循环,算出每个数字的个数,这比较简单,这里不再给出,时间复杂度O(n^2)

 

首先来看看如果可以比较大小:

时间复杂度为线性O(n),基于分治法的线性时间求主元素算法算法思想中位数:数列排序后位于最中间的那个数。如果一个数列有主元素,那么必然是其中位数。求一个数列有没有主元素,只要看中位数是不是主元素。找中位数的方法:选择一个元素作为划分起点,然后用快速排序的方法将小于它的移动到左边,大于它的移动到右边。这样就将元素划分为两个部分。此时,划分元素所在位置为k。如果k>n/2,那么继续用同样的方法在左边部分找;如果k<n/2就在右边部分找;k=n/2就找到了中位元素。根据快速排序的思想,可以在平均时间复杂度O(n)的时间内找出一个数列的中位数。然后再用O(n)的时间检查它是否是主元素。C语言源码如下:

int partition(int a[],int low,int high){    
	int pivotkey = a[low];    
	while(low<high)    
	{        
		if(low<high && a[high]>=pivotkey)           
			-–high;        
		if(low<high){
			a[low]=a[high];
			low++;
		}        
		if(low<high && a[low]<=pivotkey) 
			++low;     
		if(low<high){
			a[high]=a[low];
			--high;
		}        
	}       
	a[low]=pivotkey;      
	return low;}
//快排
void quick_sort(int a[],int low,int high){   
	if(low<high)    
	{       
		int position = partition(a,low,high);        
		if(position>n/2)           
			quick_sort(a,low,position-1);       
		else if(position<n/2)          
			quick_sort(a,position+1,high);       
		else           
			mid=a[position];//找到中位数    
	}
}
int main(){    
	int a[100];    
	printf("请输入个数n\n");   
	scanf("%d",&n);    
	for(int i=1;i<=n;i++)   
	{        
		a[i]=0;//初始化   
	}   
	for(int i=1;i<=n;i++)  
	{       
		scanf("%d",&a[i]);   
	}   
	quick_sort(a,1,n);  
	int count=0;    
	for(int i=1;i<=n;i++)//中位数个数   
	{    
		if(a[i] == mid)     
			count++;  
	}
	if(count > n / 2)      
		printf("有主元素为 %d 出现了 %d 次\n",mid,count);   
	else      
		printf("无主元素\n");   
	system("pause");
}


 

下面来开如果不可以比较大小只可以比较是否相等的情况:

下面来看看如果无序,不能比较大小的算法,具体思想就是在一个集合中,删除两个不同的数,则集合的主元素保持不变。根据这个原理,可以很快求出主元素。只有最后剩下的元素才可能是主元素。

#include <stdio.h>
int getMainElement(int a[],int len){
	int i,mainElement,repeatTimes = 0;

	//每次若不相同则减小这个计数,若相同则增加
	for(i = 0;i<len;i++){
		if(repeatTimes == 0){
			mainElement = a[i];
			repeatTimes = 1;
		}
		else{
			if(mainElement == a[i])
				repeatTimes++;
			else
				repeatTimes--;
		}
	}
	return mainElement;
}

int main(){
	while(1){
		int len,i,mainElement,flagCount = 0;
		scanf("%d",&len);
		int *a = new int[len];
		for(i = 0;i<len;i++){
			scanf("%d",&a[i]);
		}

		mainElement = getMainElement(a,len);

		for(i = 0;i<len;i++){
			if(mainElement == a[i])
				flagCount++;
		}

		if(flagCount>len/2)
			printf("%d\n",mainElement);
		else
			printf("None\n");
	}

	return 0;
}


 

 

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值