Петлевой инвариант линейного поиска
Как видно из раздела Введение в алгоритмы ( http://mitpress.mit.edu/algorithms), в упражнении говорится следующее:
Вход: массив A[1...n]
Вывод: i, где A[i]=v или NIL, если не найден
Напишите псевдокод для LINEAR-SEARCH, который просматривает последовательность, ища v. Используя инвариант цикла, докажите, что ваш алгоритм корректен. (Убедитесь, что ваш инвариант цикла выполняет три необходимых свойства - инициализация, обслуживание, завершение.)
У меня нет проблем при создании алгоритма, но я не могу понять, как я могу определить, какой у меня инвариант цикла. Мне кажется, я понял концепцию инварианта цикла, то есть условие, которое всегда истинно перед началом цикла, в конце / начале каждой итерации и по-прежнему верно, когда цикл заканчивается. Обычно это является целью, поэтому, например, при сортировке вставки, начиная с j, начиная с j=2, элементы [1, j-1] всегда сортируются. Это имеет смысл для меня. Но для линейного поиска? Я не могу думать ни о чем, просто это звучит слишком просто, чтобы думать об инварианте цикла. Я понял что-то не так? Я могу думать только о чем-то очевидном (например, NIL или между 0 и n). Заранее большое спасибо!
7 ответов
После того как вы посмотрели на индекс i
и не найден v
но что ты можешь сказать о v
что касается части массива перед i
и что касается части массива после i
?
LINEAR-SEARCH(A, ν)
1 for i = 1 to A.length
2 if A[i] == ν
3 return i
4 return NIL
Инвариант петли: в начале i
итерация for
петля (строки 1–4),
∀ k ∈ [1, i) A[k] ≠ ν.
Инициализация:
i == 1 ⟹ [1, i) == Ø ⟹ ∀ k ∈ Ø A[k] ≠ ν,
что верно, так как любое утверждение относительно пустого множества верно (пустая правда).
Обслуживание: предположим, что инвариант цикла истинен в начале i
итерация for
петля. Если A[i] == ν
текущая итерация является последней (см. раздел " Завершение "), поскольку строка 3 выполняется; в противном случае, если A[i] ≠ ν
, у нас есть
∀ k ∈ [1, i) A[k] ≠ ν and A[i] ≠ ν ⟺ ∀ k ∈ [1, i+1) A[k] ≠ ν,
это означает, что инвариантный цикл все еще будет истинным в начале следующей итерации (i+1
е).
Прекращение: for
Цикл может закончиться по двум причинам:
return i
(строка 3), еслиA[i] == ν
;i == A.length + 1
(последний тестfor
цикл), в этом случае мы находимся в началеA.length + 1
Эта итерация, следовательно, инвариант цикла∀ k ∈ [1, A.length + 1) A[k] ≠ ν ⟺ ∀ k ∈ [1, A.length] A[k] ≠ ν
и
NIL
значение возвращается (строка 4).
В обоих случаях, LINEAR-SEARCH
заканчивается, как и ожидалось.
В случае линейного поиска вариант цикла будет резервным хранилищем, используемым для сохранения индекса (вывода) .
Позволяет назвать резервное хранилище в качестве индекса, который изначально установлен в NIL. Вариант цикла должен соответствовать трем условиям:
- Инициализация: это условие выполняется для индекса variable.since, оно содержит NIL, которое может быть результатом результата и true до первой итерации.
- Обслуживание: индекс будет держать NIL, пока не будет найден элемент v. Это также верно до итерации и после следующей итерации. Так как она будет установлена внутри цикла после выполнения условия сравнения.
- Завершение: индекс будет содержать NIL или индекс массива элемента v.
,
Инвариант петли будет
forevery 0 <= i В конце цикла: если A[k] == v, то цикл завершается и выводит k если A[k]!= v и k + 1 == n (размер списка), цикл завершается со значением nil Доказательство правильности: оставлено как упражнение
Предположим, что у вас есть массив длины i, проиндексированный с [0...i-1], и алгоритм проверяет, присутствует ли v в этом массиве. Я не совсем уверен, но я думаю, что инвариант цикла выглядит следующим образом:Если j является индексом v, то [0..j-1] будет массивом, который не имеет v.
Инициализация: перед итерацией от 0..i-1 текущий проверенный массив (нет) не состоит из v.
Обслуживание: при нахождении v в j, массив из [0..j-1] будет массивом без v.
Завершение: Поскольку цикл заканчивается при нахождении v в j, [0..j-1] будет массивом без j.
Если в самом массиве нет v, то j = i-1, и вышеприведенные условия будут по-прежнему выполняться.
Инвариант линейного поиска состоит в том, что каждый элемент перед i не равен ключу поиска. Разумным инвариантом для бинарного поиска может быть диапазон [low, high), каждый элемент перед low меньше ключа, а каждый элемент после high больше или равен. Обратите внимание, что есть несколько вариантов бинарного поиска с немного отличающимися инвариантами и свойствами - это инвариант бинарного поиска с "нижней границей", который возвращает самый низкий индекс любого элемента, равный или больший, чем ключ.
Источник: https://www.reddit.com/r/compsci/comments/wvyvs/what_is_a_loop_invariant_for_linear_search/
Кажется правильным для меня.
Алгоритм LS, который я написал,
LINEARSEARCH(A, v)
for i=0 to A.length-1
if(A[i] == v)
return i
return NIL
Я сделал свои собственные предположения об инварианте цикла для проверки правильности линейного поиска..... Возможно, это совершенно неправильно, поэтому мне нужны предложения относительно моих предположений.
1) При Инициализации - при i = 0, мы ищем v при i = 0.
2) На последовательных итерациях - мы ищем v, пока i 3) В конце-я = A.length и до A.length мы продолжали искать v.