众数

一.问题

  • 在任一无序向量中A中,若有一半以上的元素的数值同为m,则称m为A的众数。

二.减而治之

通过减治策略计算众数

  • 设P为向量A中长度为2m的前缀。若元素x在P中恰好出现m次,则A有众数仅当后缀A-P拥有众数,且A-P的众数就是A的众数。
  • 这里只考虑A拥有众数的情况,若A的众数就是x,则在剪除前缀P之后,x与非众数均减少相同的数目,二者数目差距在后缀A-P中保持不变。反过来,若A的众数为 y ≠ x,则在剪除前缀P之后,y减少的数目也不致多于非众数减少的数目,二者数目差距在后缀A-P中也不会缩小。

三.实现

template <typename T> bool majority(Vector <T> A , T & maj ) { //众数查找算法:T可比较可判等
	maj = majEleCandidate ( A ); //必要性:选出候选者maj
	retrurn majEleCheck( A , maj ); //充分性:验证maj是否的确当选
}
template <typename T> bool majEleCheck( Vector <T> A , T maj ) { //验证候选者是否确为众数
	int occurrence = 0; //maj在A[ ]中出现的次数
	for( int i=0 ; i < A.size() ; i++ )  //逐一遍历A[]中各个元素
		if( A[i] == maj ) occurrence++ ; //每遇到一次maj,均更新计数器
	return 2 * occurrence > A.size(); //根据最终的计数量,即可判断是否的确当选
}
template <typename T> T majEleCandiate (Vector <T> A) { //选出具备必要条件的众数候选者
	T maj; //众数候选者
	for( int c = 0, i = 0 ; i < A.size() ; i++ ){ //线性扫描:借助计数器c ,记录maj与其他元素的数量差额
		if( 0 == c ) { //每当c归零,都意味着此时的前缀P可以剪除
			maj = A[i] ; c=1 ;//众数候选者改为新的当前元素
		} else 
			maj == A[i] ? c++ : c-- ; //相应的更新差额计数器
	return maj; //原向量的众数若存在,则只能是maj		
	}
}

四.代码分析

  • 变量maj始终为当前前缀中出现次数不少于一半的某个元素;c则始终记录该元素与其它元素的数目之差。一旦c归零,则意味着上图所示,在当前向量中找到了一个可剪除的前缀。在剪除该前缀后,问题范围将相应地缩小至A-P。此后,只需将maj重新初始化为A-P的首元素,并令c = 1,即可继续重复上述迭代过程。
  • 减而治之,随着算法进行的同时,待求解问题的规模都缩减一个常数,直至最终蜕化为平凡小的问题。仔细研究**majEleCandidate()**函数,发现随着扫描的进行,若c归零,则相当于抛弃掉了A[i]之前的元素,这时向量的规模变小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值