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