Najlepszy algorytm do sprawdzenia, czy lista połączona ma cykl

Jaki jest najlepszy (wstrzymujący) algorytm do określania, czy lista linkowana ma w sobie cykl?

[Edytuj] Analiza asymptotycznej złożoności zarówno dla czasu, jak i przestrzeni byłaby słodka, więc odpowiedzi można lepiej porównać.

[Edytuj] pierwotne pytanie nie dotyczyło węzłów z outdegree > 1, ale niektórzy o tym mówią. To pytanie jest bardziej podobne do "najlepszego algorytmu do wykrywania cykli w grafie skierowanym".

Author: eeerahul, 2008-08-29

13 answers

Wykonaj dwa wskaźniki iteracyjne przez Listę; wykonaj jeden iteracyjny z dwukrotnie większą prędkością niż drugi i porównaj ich pozycje na każdym kroku. Z czubka głowy, coś w stylu:

node* tortoise(begin), * hare(begin);
while(hare = hare->next)
{
    if(hare == tortoise) { throw std::logic_error("There's a cycle"); }
    hare = hare->next;
    if(hare == tortoise) { throw std::logic_error("There's a cycle"); }
    tortoise = tortoise->next;
}

O(n), który jest tak dobry, jak tylko możesz.

 49
Author: DrPizza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-03 06:04:58

Warunek wstępny: śledzenie rozmiaru listy (aktualizowanie rozmiaru po dodaniu lub usunięciu węzła).

Detekcja pętli:

  1. Zachowaj licznik podczas przechodzenia przez rozmiar listy.

  2. Jeśli licznik przekroczy rozmiar listy, możliwy jest cykl.

Złożoność: O (n)

Uwaga: porównanie licznika i rozmiaru listy, jak również operacja aktualizacji rozmiaru listy, muszą być bezpieczne dla wątku.

 1
Author: kean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-16 22:18:58

Weź dwa wskaźniki * p I * q, zacznij przemierzać połączoną listę " LL "używając obu wskaźników:

1) wskaźnik p usunie poprzedni węzeł za każdym razem i wskaże następny węzeł.

2) Wskaźnik q będzie poruszał się za każdym razem tylko w kierunku do przodu.

Warunki:

1) wskaźnik p wskazuje na null, a q wskazuje na jakiś węzeł: loop is present

2) oba wskaźniki wskazujące na null: nie ma pętli

 1
Author: mayank joshi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-24 10:17:57

A co z użyciem tabeli hash do przechowywania już widzianych węzłów (patrzysz na nie w kolejności od początku listy)? W praktyce można osiągnąć coś bliskiego O (N).

W przeciwnym razie, użycie posortowanej sterty zamiast tabeli hash uzyskałoby O (N log (N)).

 0
Author: OysterD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-29 09:33:50

Zastanawiam się, czy jest jakiś inny sposób niż po prostu iteracyjnie-wypełniaj tablicę, gdy robisz krok do przodu i sprawdź, czy bieżący węzeł jest już obecny w tablicy...

 0
Author: Henrik Paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-29 09:34:45

Algorytm Konrada Rudolfa nie zadziała, jeśli cykl nie wskazuje na początek. Poniższa lista uczyni ją nieskończoną pętlą: 1->2->3->2.

Algorytm Drpizzy jest zdecydowanie najlepszym rozwiązaniem.

 0
Author: Liedman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-29 09:46:24

W tym przypadku kod Osterda będzie najszybszym rozwiązaniem (kolorowanie wierzchołków)

To by mnie naprawdę zaskoczyło. Moje rozwiązanie wykonuje co najwyżej dwa przejścia przez Listę (jeśli ostatni węzeł jest połączony z przedostatnim lodem), a w powszechnym przypadku (brak pętli) zrobi tylko jedno przejście. Bez hashowania, bez alokacji pamięci itp.
 0
Author: DrPizza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-29 09:52:44

W tym przypadku kod Osterda będzie najszybszym rozwiązaniem (kolorowanie wierzchołków)

To by mnie naprawdę zaskoczyło. Moje rozwiązanie wykonuje co najwyżej dwa przejścia przez Listę (jeśli ostatni węzeł jest połączony z przedostatnim lodem), a w powszechnym przypadku (brak pętli) zrobi tylko jedno przejście. Bez hashowania, bez alokacji pamięci itp.
Tak. Zauważyłem, że preparat nie był doskonały i przeformułowałem go. Nadal wierzę, że sprytne hasanie może działać szybciej-o włos. Uważam, że Twój algorytm jest najlepszym rozwiązaniem.

Żeby podkreślić mój punkt widzenia: kolorowanie vertec jest używane do wykrywania cykli w zależności przez współczesnych śmieciarzy, więc istnieje bardzo realny przypadek użycia. Najczęściej używają bitowych FLAG do wykonywania kolorowania.

 0
Author: Konrad Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-29 09:58:35

Będziesz musiał odwiedzić każdy węzeł, aby to określić. Można to zrobić rekurencyjnie. Aby zatrzymać odwiedzanie już odwiedzonych węzłów, potrzebujesz flagi z napisem "już odwiedzone". To oczywiście nie daje pętli. Więc zamiast flagi bitowej, użyj liczby. Zacznij od 1. Sprawdź połączone węzły, a następnie zaznacz je jako 2 i rekurencyjnie, dopóki sieć nie zostanie pokryta. Jeśli podczas sprawdzania węzłów napotkasz węzeł, który jest o więcej niż jeden mniejszy od bieżącego węzła, masz cykl. Długość cyklu jest podana przez różnicę.

 0
Author: Guillermo Phillips,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-26 15:05:15

Dwa wskaźniki są inicjowane na początku listy. Jeden wskaźnik do przodu raz na każdym kroku, a drugi do przodu dwa razy na każdym kroku. Jeśli szybszy wskaźnik spotka się ponownie z wolniejszym, na liście znajduje się pętla. W przeciwnym razie nie ma pętli, jeśli szybsza dotrze do końca listy.

Poniższy przykładowy kod jest zaimplementowany zgodnie z tym rozwiązaniem. Szybszy wskaźnik to pFast, a wolniejszy pSlow.

bool HasLoop(ListNode* pHead)
{
    if(pHead == NULL)
        return false;


    ListNode* pSlow = pHead->m_pNext;
    if(pSlow == NULL)
        return false;


    ListNode* pFast = pSlow->m_pNext;
    while(pFast != NULL && pSlow != NULL)
    {
        if(pFast == pSlow)
            return true;


        pSlow = pSlow->m_pNext;


        pFast = pFast->m_pNext;
        if(pFast != NULL)
            pFast = pFast->m_pNext;
    }


    return false;
}

To rozwiązanie jest dostępne na mój blog . Jest kolejny problem omówiony na blogu: co to jest węzeł wejściowy, gdy na liście jest cykl / pętla?

 0
Author: Harry He,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-28 13:41:04

Rozwiązanie"Hack "(powinno działać w C / C++):

  • przemierzaj listę i ustaw ostatni bit wskaźnika next na 1.
  • jeśli znajdziesz element z oznaczonym wskaźnikiem -- zwróć true i pierwszy element cyklu.
  • Przed Powrotem zresetuj wskaźniki z powrotem, chociaż wierzę, że dereferencja będzie działać nawet z oznaczonymi wskaźnikami.

Złożoność czasu wynosi 2n. wygląda na to, że nie używa żadnych zmiennych czasowych.

 0
Author: Ayrat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-31 08:02:21

Jest to rozwiązanie wykorzystujące tabelę skrótów (w rzeczywistości tylko listę) do zapisania adresu wskaźnika.

def hash_cycle(node):
    hashl=[]
    while(node):
        if node in hashl:
            return True
        else:
            hashl.append(node)
            node=node.next
    return False
 0
Author: FlyingAura,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-19 08:16:32

Def has_cycle(head): counter = set ()

while head is not None:
    if head in counter:
        return True
    else:
        counter.add(head)
        head = head.next
 0
Author: ericgu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-16 14:54:41