正如Ariel所指出的,下面给出了标准的最大查找算法:
def find_maximum(a):
m = a[0]
for x in a:
if x > m: m = x
return m
实际上,只要保持以下条件,它们将可以正常工作:
- 可以比较任何一对元素,并且
- 确保输入中包含最大元素,即成对大于输入中任何其他元素的元素。
(上面的第一个假设实际上可以放宽,即使不必修改算法,只要我们假设最大元素与其他所有元素都具有可比性,并且x > y
如果这些元素x
与y
不可比,则始终为假。)
特别是,您声称:
[…]可以肯定地说,该元素需要与其他所有元素进行显式比较(因为比较不是可传递的)。
在上面给出的假设下是不正确的。实际上,要证明上述算法将始终找到最大元素,只需观察到以下内容即可:
- 由于循环遍历所有输入元素,因此在某些迭代
x
中将是最大元素;
- 由于最大元素成对大于每个其他元素,因此在迭代结束时
m
将成为最大元素;和
- 由于没有其他元素可以成对大于最大元素,因此
m
在任何后续迭代中都不会改变。
因此,m
如果输入包含一个元素,则在循环结束时,它将始终是最大元素。
附言 如果输入的信息并不一定总是包含一个极大元,然后验证事实的确需要测试的候选答案对所有其他元素,以验证它确实是最大的。但是,在运行上面的最大查找算法之后,我们仍然可以在O(n)时间内执行此操作:
def find_maximum_if_any(a):
# step 1: find the maximum, if one exists
m = a[0]
for x in a:
if x > m: m = x
# step 2: verify that the element we found is indeed maximal
for x in a:
if x > m: return None # the input contains no maximal element
return m # yes, m is a maximal element
(我在这里假设关系>
是不自反的,即没有元素可以大于自身。如果不是这种情况,x > m
则应将第2步中的比较替换为x ≠ m and x > m
,其中≠
表示身份比较。或者我们可以应用优化如下所述。)
为了证明算法变体的正确性,请考虑两种可能的情况:
- 如果输入包含最大元素,则第1步将找到它(如上所示),第2步将确认它。
- 如果输入没有不含有最大元素,则步骤1将最终挑选一些任意元素
m
。不管是哪个元素,因为它在任何情况下都是非最大的,因此步骤2将检测到该元素并返回None
。
如果我们将m
in 的索引存储在输入数组中a
,则实际上可以优化步骤2以仅检查m
in 之前的那些元素a
,因为已经将较晚的元素与m
步骤1 进行了比较。但是此优化不会改变渐近时间的复杂性的算法,仍然是O(n)。