Как отмечает Ариэль , стандартный алгоритм максимального поиска приведен ниже:
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
всегда будет максимальный элемент, если вход содержит один элемент.
Ps. Если входные данные не обязательно всегда содержат максимальный элемент, то проверка этого факта действительно потребует проверки ответа кандидата на каждый другой элемент, чтобы убедиться, что он действительно максимальный. Тем не менее, мы можем сделать это за 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
в входном массиве a
, мы могли бы на самом деле оптимизировать шаг 2 , чтобы проверить только те элементы , которые приходят , прежде чем m
в памяти a
, поскольку любые последующих элементы уже по сравнению с m
в шаге 1. Но эта оптимизация не изменяет асимптотическую сложность времени алгоритма, который по-прежнему O ( n ).