[C算法]003-寻找主元素
均采用 C 语言来编写,版本为 C17,使用其他版本也可以,仅仅停留在算法层面,各大版本几乎区别不大
题目
2013年统考真题
已知一个整数序列 ,其中 。
若存在 且 ,则称 为主元素。
若 ,则 为主元素;
若 ,则没有主元素;
分析
这个题目是在求 过半数 的众数,那我们就要拿出大名鼎鼎的 摩尔投票算法 (Boyer-Moore Voting Algorithm),它最擅长的就是求 过半数 的众数。
摩尔投票算法
摩尔投票算法(Boyer-Moore Voting Algorithm)是一种用于在 时间复杂度和 空间复杂度下,从数组中找出众数(出现次数超过数组长度一半的元素)的高效算法。
以下是关于该算法的详细讲解:
-
核心思想:同归于尽
摩尔投票算法的直观理解是“对拼消耗”。
想象一个战场,不同的数字代表不同的阵营。如果两个不同阵营的人遇到,就同归于尽;如果遇到同阵营的人,就加入队伍。
由于众数的出现次数超过了总数的一半(即 ),那么即使众数与其他所有非众数进行一对一抵消,最后剩下的也一定会是众数。 -
算法步骤
算法分为两个阶段:-
第一阶段:寻找候选人(Candidate)
- 初始化一个候选人
candidate为任意值,计数器count为 0。 - 遍历数组中的每个元素
x:- 如果
count == 0,则将当前元素x设为candidate,并将count设为 1。 - 否则,如果
x == candidate,则count加 1。 - 否则(即
x != candidate),则count减 1。
- 如果
- 初始化一个候选人
-
第二阶段:验证候选人(可选)
由于第一阶段得到的候选人不一定真的是众数(例如数组为
[1, 2, 3]时,最后剩下的可能是 3,但 3 并不是众数),如果题目不保证一定存在众数,则需要再次遍历数组,统计该候选人的出现次数。如果次数大于 ,则确定为众数。 -
-
图解示例
假设数组为:
[2, 2, 1, 1, 1, 2, 2]- 遇到 2:
count=0,设置candidate=2, count=1 - 遇到 2:等于候选人,
count=2 - 遇到 1:不等于候选人,
count=1(抵消一次) - 遇到 1:不等于候选人,
count=0(抵消一次) - 遇到 1:
count=0,设置candidate=1, count=1 - 遇到 2:不等于候选人,
count=0(抵消一次) - 遇到 2:
count=0,设置candidate=2, count=1
最后
candidate为 2。 - 遇到 2:
-
复杂度分析
- 时间复杂度:。只需要对数组进行一到两次遍历。
- 空间复杂度:。只需要常数级别的额外空间来存储
candidate和count。
-
算法扩展
摩尔投票算法还可以扩展到寻找出现次数超过 的元素。
例如,寻找出现次数超过 的元素,此时最多会有 2 个这样的候选人。我们需要维护两个候选人和两个计数器,当遇到与两个候选人都不相等的元素时,两个计数器同时减 1。
代码实现
1 | int find_main_number(int a[], int len) { |
两次循环
复杂度分析的目的是为了区分不同“数量级”的算法。
- :线性增长。即使是 (循环10次),它依然比 (如排序算法)或 (如嵌套循环)在数据量极大时快得多。
- 对比:
- 如果 :
- 大约执行 200 万次操作。
- 大约执行 1,000,000,000,000(一万亿)次操作。
- 可以看到,多跑一轮循环带来的开销,在不同数量级的差距面前是微不足道的。
- 对比:
虽然两次循环在实际运行时间上确实比一次循环慢一点(大约慢一倍),但在算法理论层面,它依然属于最高效的线性时间复杂度 ,这比任何基于排序()的方法都要快。
- 标题: [C算法]003-寻找主元素
- 作者: Lucas
- 创建于 : 2025-12-25 14:48:19
- 更新于 : 2025-12-25 20:25:37
- 链接: https://darkflamemasterdev.github.io/2025/12/25/C算法-003-寻找主元素/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。