Обнаружение цикла в связанном списке с использованием подхода зайца и черепахи

Я понимаю, что для обнаружения цикла в связанном списке я могу использовать подход зайца и черепахи, который содержит 2 указателя (медленные и быстрые). Однако, прочитав в wiki и других ресурсах, я не понимаю, почему гарантируется, что два указателя встретятся в o(n) сложности времени.

3 ответов


вот попытка неофициального доказательства.

форма цикла не имеет значения. Он может иметь длинный хвост и петлю к концу, или просто петлю от начала до конца без хвоста. Независимо от формы цикла, ясно одно - что черепаший указатель не может догнать Заячий указатель. Если они когда-нибудь встретятся, указатель зайца должен догнать указатель черепахи сзади.

С этим установлено, рассмотреть две возможности:

  1. указатель зайца находится на один шаг позади указателя черепахи.
  2. указатель зайца находится на два шага позади указателя черепахи.

все большие расстояния в конечном итоге уменьшатся до одного или двух.

предполагая, что указатель черепахи всегда движется первым (может быть и наоборот), то в первом случае указатель черепахи делает один шаг вперед. Сейчас расстояние между ними 2. Когда указатель зайца делает 2 шага сейчас они приземлятся на одном узле. Вот то же самое проиллюстрировано для облегчения понимания. Слишком много текста может помешать.

♛ = hare
♙ = tortoise
X = both meet

..♛♙... #1 - Initially, the hare is one step behind the tortoise.
..♛.♙.. #2 - Now the tortoise takes one step. now hare is two steps behind.
....X.. #3 - Next, the hare takes two steps and they meet!

теперь давайте рассмотрим второй случай, когда расстояние между ними 2. Медленный указатель перемещается на один шаг вперед, и расстояние между ними становится 3. Затем быстрый указатель перемещается вперед на два шага, и расстояние между ними уменьшается до 1, что идентично первому случаю, в котором мы уже доказали, что они встретятся в одном еще шаг. Опять же, иллюстрированный для облегчения понимания.

.♛.♙... #1 - Initially, the hare is two steps behind the tortoise.
.♛..♙.. #2 - Now the tortoise takes one step and they become three steps apart.
...♛♙.. #3 - Next, the hare takes two steps which is identical to previous case.

теперь, что касается того, почему этот алгоритм гарантированно находится в O (n), используйте то, что мы уже установили, что заяц будет встречайте черепаху, прежде чем она двинется вперед. Это означает, что, как только оба окажутся внутри петли, прежде чем черепаха завершит очередной раунд, она встретится с зайцем, так как заяц движется вдвое быстрее. В худшем случае цикл будет представлять собой круг с n узлами. Пока черепаха может только завершите один раунд за n шагов, заяц может завершить два раунда за это время. Даже если заяц пропустил черепаху в первом раунде (что он и сделает), он определенно догонит черепаху во втором раунде.


пусть итераторы A и B пройтись по списку соответственно по одному и по двое. Consdier существует цикл. Тогда в тот момент, когда A входит в цикл,B уже будет где-то внутри него. Если длина цикла K, потом B будет бегать вокруг него в ]K/2[ движется, так что самое большее в 2*]K/2[ итераций мы получим ситуацию, когда B появляется из-за A на расстоянии 1: B->A или 2: B->.->A, и B'й очереди. После этого, очевидно, они встретятся либо в 1 или 2 движется. Итак, если цикл существует и начинается с некоторой позиции P, тогда мы делаем самое большее 2*P + 2*]K/2[ + 2 = O(N) итераций.


//if you just want to check if there is a loop

loop = false;
item = head-of-list; 
while (item != nil)
{
   if (item.next < 0) 
   {
      loop = true; 
      break; 
   }
   else
   {
      actual = item;
      item = item.next; 
      actual.next = actual.next * -1; 
   }
} 

return loop;