Инвариант цикла линейного поиска

Как видно из раздела «Введение в алгоритмы» (http://mitpress.mit.edu/algorithms), в упражнении говорится следующее:

Входные данные: массив A[1..n] и значение v

Вывод: индекс i, где A[i] = v или NIL, если v не найдено в A

Напишите псевдокод для LINEAR-SEARCH, который сканирует последовательность в поисках v. Используя инвариант цикла, докажите, что ваш алгоритм верен. (Убедитесь, что ваш инвариант цикла удовлетворяет трем необходимым свойствам — инициализация, обслуживание, завершение.)

У меня нет проблем с созданием алгоритма, но чего я не понимаю, так это того, как я могу решить, каков мой инвариант цикла. Я думаю, что понял концепцию инварианта цикла, то есть условия, которое всегда истинно перед началом цикла, в конце/начале каждой итерации и остается истинным, когда цикл заканчивается. Обычно это и является целью, например, в сортировка вставками, перебирая j, начиная с j = 2, A[1..j-1] элементов всегда сортируются. Это имеет смысл для меня. Но для линейного поиска? Я ничего не могу придумать, это звучит слишком просто, чтобы думать об инварианте цикла. Я что-то не так понял? Я могу думать только о чем-то очевидном, например (это либо NIL, либо между 0 и n). Заранее большое спасибо!


person Clash    schedule 07.04.2011    source источник


Ответы (7)


После того, как вы просмотрели индекс i и еще не нашли v, что вы можете сказать о v в отношении части массива до i и в отношении части массива после i?

person Svante    schedule 07.04.2011
comment
v не от 1 до i, но может быть после i, может ли это быть инвариантом цикла? - person Clash; 07.04.2011
comment
хорошо, это не имеет смысла... как насчет того, что v не из [1...i], но это будет недействительно для инициализации цикла, так как i=1, и я не могу гарантировать, что v не первый элемент. Но я тоже не могу использовать отрицательные границы, верно? - person Clash; 07.04.2011
comment
Столкновение, взгляните на мой ответ ниже. - person Larry Watanabe; 07.04.2011
comment
@Clash: Ваша первая попытка выглядит разумной. Мою подсказку лучше сформулировать так: Прежде чем смотреть на A[i] ..., чтобы инвариант сохранялся в начале цикла. - person Svante; 07.04.2011
comment
для новой переменной k ‹ i все элементы от A до индекса k не равны v. Но мне все равно кажется это странным, как если бы i равно 0, это означало бы, что k = -1, которого нет в A... равно есть способ сформулировать это лучше? Или это не проблема, что k=-1? Могу ли я тогда сказать, что A[0...i-1] не v? Даже если это будет представлять невозможный вектор (для i = 0)? Как А [0 ... -1] - person Clash; 08.04.2011
comment
@Clash: текст вашего упражнения, похоже, подразумевает массив с отсчетом от 1. i затем переходит от 1 к n. Если вы инициализируете i значением 1, затем проверяете A[i] и, наконец, увеличиваете i, ваш инвариант цикла сохраняется для любого индекса массива меньше i. Если нет допустимого индекса массива, меньшего, чем i, он тривиально считает, что все верно для пустого множества. - person Svante; 08.04.2011
comment
@Clash: это не проблема. Помните, что это псевдокод и математика, а не реальный код на реальных машинах. Если вы предполагаете, что нотация A[l...u] представляет { A[i], ∀i i>=l ∧ i <= u }, то A[0...-1] будет представлять пустой набор. Утверждение, что v не находится на пустом множестве, верно, поэтому оно верно в начале. - person R. Martinho Fernandes; 08.04.2011
comment
Отлично, это были мои сомнения. Спасибо, парни! - person Clash; 08.04.2011

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+1th).

Завершение: цикл for может завершиться по двум причинам:

  1. return i (строка 3), если A[i] == ν;
  2. 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 заканчивается, как и ожидалось.

person Joyce    schedule 09.08.2018
comment
Красивый! Математически точный и очень хорошо выставленный. Спасибо за этот ответ! - person Otavio Macedo; 30.10.2019

В случае линейного поиска вариантом цикла будет резервное хранилище, используемое для сохранения index(output) .

Давайте назовем резервное хранилище как index, для которого изначально установлено значение NIL. Вариант цикла должен соответствовать трем условиям:

  • Инициализация: это условие выполняется для индексной переменной, поскольку оно содержит NIL, что может быть результатом и истинным до первой итерации.
  • Обслуживание: индекс будет содержать NIL до тех пор, пока элемент v не будет найден. Это также верно до итерации и после следующей итерации. Так как она будет установлена ​​внутри цикла после успешного выполнения условия сравнения.
  • Завершение: индекс будет содержать NIL или индекс массива элемента v.

.

person ani07    schedule 05.05.2016

Инвариант цикла будет

forevery 0 ‹= i ‹ k, где k — текущее значение переменной итерации цикла, A[i] != v

При завершении цикла:

если A[k] == v, то цикл завершается и выводит k

если A[k] != v и k + 1 == n (размер списка), то цикл завершается со значением nil

Доказательство правильности: оставлено в качестве упражнения

person Larry Watanabe    schedule 07.04.2011
comment
Справедливо ли это для инициализации? 0 ‹= i ‹ k будет означать, что i при инициализации пусто, null или что-то в этом роде? - person Clash; 07.04.2011
comment
Я не могу это доказать, потому что у меня нет вашего кода. Но у меня внутри цикла был бы оператор if-then-else, говорящий что-то вроде if A[i[ == v, return i. Тогда я мог бы доказать случай инициализации для моего кода: k = 0. Либо A[i] == v, и в этом случае мой цикл завершается и выводит k. И наоборот, если A[i] != v, то для всех 0 ‹= i ‹= 0 A[i] != v. - person Larry Watanabe; 08.04.2011
comment
0 <= i < k выполняется для начальной итерации цикла, так как вы получите пустой массив, который, по сути, не включает v, следовательно, условие истинно до начального выполнения цикла. - person fnisi; 05.06.2019

Предположим, что у вас есть массив длины 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, и вышеуказанные условия по-прежнему будут выполняться.

person Mayank Shah    schedule 17.11.2017

Инвариант для линейного поиска состоит в том, что каждый элемент до i не равен ключу поиска. Разумным инвариантом для бинарного поиска может быть диапазон [низкий, высокий), каждый элемент перед низким меньше ключа, а каждый элемент после старшего больше или равен. Обратите внимание, что существует несколько вариантов бинарного поиска с немного отличающимися инвариантами и свойствами — это инвариант для бинарного поиска с «нижней границей», который возвращает наименьший индекс любого элемента, равного или превышающего ключ.

Источник: https://www.reddit.com/r/compsci/comments/wvyvs/what_is_a_loop_invariant_for_linear_search/

Мне кажется правильным.

person Prashant N    schedule 27.08.2017

Алгоритм 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 ‹ A.length-1

  3. В конце- i = A.length и до A.length мы продолжали искать v.

person Abhay_maniyar    schedule 10.08.2016