有,而且不需要元素有顺序。
正式地说,我们正在处理multisets(也称为bags。)在下面,对于多重集S,让:
-
v(e,S) 是元素e在S中的多重性,即它出现的次数(如果e根本不是S的成员,则多重性为零。)
-
#S 是 S 的基数,即 S 中的元素个数计数多重性。
- ⊕ 是多集和:如果 S = L ⊕ R 那么 S 包含所有元素L和R计数重数,即v(e;S) = v(e;L) + v(e;R) 用于任何元素 e。 (这也说明多重性可以通过‘分而治之’来计算。)
- [x]是小于等于x的最大整数。
S 的多数元素 m,如果存在的话,是那个元素,使得 2 v(m;S) > #S.
我们称 L 和 R 为 S 的 分裂 如果 L ⊕ R = S 和一个偶分裂 if |#L - #R| ≤ 1。即如果 n=#S 是偶数,则 L 和 R 正好有一半的元素S,如果 n 是奇数,则一个具有基数 [n/2] 而另一个具有基数 [n/2]+1.
对于将 S 任意拆分为 L 和 R,有两个观察结果:
如果 L 和 R 都没有多数元素,则 S 不能:对于任何元素 e em>, 2 v(e;S) = 2 v(e ;L) + 2 v(e;R) ≤ #L + #R = #S.
如果 L 和 R 之一的多数元素 m 具有多重性 k,则它是S的多数元素,只有当它在另一半有多重性r,有2(k+r em>) > #S.
下面的算法 majority(S) 返回一对 (m,k),表示m 是出现 k 次的多数元素,或者 none:
- 如果S为空,返回none;如果S只有一个元素m,则返回(m,1)。否则:
- 将S平均分成两半L和R。
-
令 (m,k) = majority(L),如果不是 none:
一个。令 k' = k + v(m;R)。 p>
b.如果 2 k' > n,则返回 (m,k')。
-
否则让 (m,k) = majority(R),如果不是 none :
一个。令 k' = k + v(m;L)。 p>
b.如果 2 k' > n,则返回 (m,k')。
- 否则返回无。
请注意,即使拆分不是偶数,该算法仍然是正确的。尽管在实践中平均分配可能会表现得更好。
附录
在上面的算法描述中明确了终端情况。一些示例 C++ 代码:
struct majority_t {
int m; // majority element
size_t k; // multiplicity of m; zero => no majority element
constexpr majority_t(): m(0), k(0) {}
constexpr majority_t(int m_,size_t k_): m(m_), k(k_) {}
explicit operator bool() const { return k>0; }
};
static constexpr majority_t no_majority;
size_t multiplicity(int x,const int *arr,size_t n) {
if (n==0) return 0;
else if (n==1) return arr[0]==x?1:0;
size_t r=n/2;
return multiplicity(x,arr,r)+multiplicity(x,arr+r,n-r);
}
majority_t majority(const int *arr,size_t n) {
if (n==0) return no_majority;
else if (n==1) return majority_t(arr[0],1);
size_t r=n/2;
majority_t left=majority(arr,r);
if (left) {
left.k+=multiplicity(left.m,arr+r,n-r);
if (left.k>r) return left;
}
majority_t right=majority(arr+r,n-r);
if (right) {
right.k+=multiplicity(right.m,arr,r);
if (right.k>r) return right;
}
return no_majority;
}