Trouver en boucle dans une seule liste liée
Comment puis-je détecter que si une seule liste liée a boucle ou pas??
Si elle a de la boucle alors comment trouver le point de départ de la boucle, c'est à dire le nœud à partir duquel la boucle a commencé.
- Trouver des boucles dans une liste chaînée est discuté dans la des Éléments de Programmation, pas de doute, parmi beaucoup d'autres endroits.
- Une autre explication de l'algorithme qui peut également trouver de premier cycle de l'élément: marcin-chwedczuk.github.io/...
- possible en double stackoverflow.com/questions/2936213/...
- Double Possible de Comment détecter une boucle dans une liste?
- Un de mes amis m'a posé cette question et il m'a permis d'y arriver avec O(1) de la complexité, et je suis toujours bloqué avec ça. Quelqu'un peut résoudre mon problème ? Merci
Vous devez vous connecter pour publier un commentaire.
Vous pouvez détecter simplement en exécutant deux pointeurs par le biais de la liste, ce processus est connu comme la tortue et le lièvre algorithme d'après la fable du même nom.
Tout d'abord, vérifiez si la liste est vide (
head
estnull
). Si oui, aucune boucle n'est possible afin d'arrêter maintenant.Sinon, le début de la première pointeur
tortoise
sur le premier nœudhead
, et le deuxième pointeurhare
sur le second nœudhead.next
.Puis une boucle continue jusqu'à ce que
hare
estnull
(qui peut être déjà le cas dans un élément de liste), l'avancement detortoise
par un ethare
par deux à chaque itération. Le lièvre est garanti d'atteindre la fin de la première (si il y est fin) depuis qu'il a commencé à l'avance et s'exécute plus rapidement.Si il n'y a pas de fin (c'est à dire, si il y a une boucle), il finira par pointer vers le même nœud et vous pouvez vous arrêter, en sachant que vous avez trouvé un nœud quelque part à l'intérieur de la boucle.
Envisager la boucle suivante, qui commence à
3
:De départ
tortoise
à 1 ethare
à 2, ils prennent les valeurs suivantes:Parce qu'ils deviennent égaux à
(6,6)
, et depuishare
devrait toujours être au-delà detortoise
dans un non-bouclage de la liste, cela signifie que vous avez découvert une boucle.Le pseudo-code d'aller quelque chose comme ceci:
Le temps de la complexité de cet algorithme est
O(n)
puisque le nombre de nœuds visités (par tortue et le lièvre) est proportionnelle au nombre de nœuds.Une fois que vous savez un nœud dans la boucle, il y a aussi un
O(n)
méthode garantie pour trouver le commencer de la boucle.Nous allons revenir à la position initiale après que vous avez trouvé un élément quelque part dans la boucle, mais vous ne savez pas où le début de la boucle.
C'est le processus à suivre:
hare
et définirsize
à1
.hare
ettortoise
sont différents, continuer à avancerhare
, l'augmentation desize
à chaque fois. Ce terme donne la taille de la boucle, six dans ce cas.size
est1
, cela signifie queyou must *already* be at the start of the loop (in a loop of size one, there is only one possible node that can *be* in the loop so it *must* be the first in that loop). In this case, you simply return
lièvre " que le début, et passer le reste de la procédure ci-dessous.hare
ettortoise
à la première élément de la liste et de faire progresserhare
exactementsize
fois (à la7
dans ce cas). Cela donne deux pointeurs qui sont différents par exactement la taille de la boucle.hare
ettortoise
sont différents, les faire progresser ensemble (avec le lièvre à courir à un rythme plus calme, la même vitesse que la tortue - je suppose qu'il est fatigué de son premier run). Depuis, ils resteront exactementsize
éléments les uns des autres en tout temps,tortoise
sera atteindre le début de la boucle, à l' exactement même temps quehare
retourne le début de la boucle.Vous pouvez le voir avec la suite de la soluce:
Donc
3
est le point de départ de la boucle, et depuis ces deux opérations (la détection de boucle et le début de la boucle de découverte) sontO(n)
et réalisées de façon séquentielle, le tout pris dans leur ensemble est égalementO(n)
.Si vous voulez une preuve formelle que cela fonctionne, vous pouvez consulter les ressources suivantes:
Si vous êtes tout simplement après l'appui de la méthode (pas de preuve formelle), vous pouvez exécuter les opérations suivantes à Python 3 programme qui évalue sa maniabilité pour un grand nombre de tailles (nombre d'éléments dans le cycle) et de plomb-ins (éléments avant le début du cycle).
Vous verrez qu'il trouve toujours un point où les deux pointeurs de répondre:
B
par une au début de chaque cycle est de s'assurer qu'il n'est pas démarrer en étant égal àA
. C'est parce queA == B
est le signal queC
n'est pas encore dans la boucle (B
a exécuté la totalité de la boucle sans trouverC
). Si nous commençons avecA == B
, le cycle se terminer immédiatement.1 (2 3 4 5)
avec la boucle indiqué entre parenthèses (5
points de retour à2
). La séquence de(a,b)
est alors(1,2) [(2,5) (3,4) (4,3) (5,2)] [(2,5) (3,4) (4,3) (5,2)] ... ad infinitum
et les pointeurs jamais deviennent égaux.C'est parce qu'il y a de la boucle de tailles qui vont provoquerb
ignore toujours plus dea
chaque passage dans la boucle, quelque chose qui est impossible si vous êtes en utilisant1
et2
que les incréments.La réponse choisie donne un O(n*n) solution pour trouver le nœud de départ du cycle. Voici un O(n) solution:
Une fois que nous trouvons le lent et Un rapide B dans le cycle, faire l'un d'entre eux et de l'autre continuer à aller un pas à chaque fois, pour décider du périmètre de la cycle de, disons, P.
Ensuite, nous avons un nœud à la tête et le laisser aller P étapes, et mettre un autre nœud à la tête. Nous avance ces deux nœuds à la fois une étape, à chaque fois, lors de leur première rencontre, c'est le point de départ du cycle.
Vous pouvez utiliser hachage carte pour trouver si un lien de la liste ont en boucle ou non ci-dessous utilise la fonction de hachage de la carte pour savoir si le lien de la liste ont en boucle ou pas
Deux pointeur de la méthode est la meilleure approche, car le temps de la complexité est O(n) Hachage Carte requise plus O(n) l'espace de la complexité.
J'ai lu cette réponse dans la structure de Données livre de Narasimha Karamanchi.
Nous pouvons utiliser Floyd cycle de l'algorithme de recherche de, aussi connu comme tortue et le lièvre algorithme. En cela, les deux pointeurs sont utilisés; un (dire
slowPtr
) est avancée par un seul nœud, et un autre (fastPtr
) est avancé par les deux nœuds. Si une boucle est présent dans la liste liée, ils sauront répondre à un certain point.Si il existe une boucle puis nous point l'un des pointeurs à la tête et avance désormais tous les deux par un seul nœud. Le nœud sur lequel ils sont le commencer nœud de la boucle dans l'unique liste liée.
Pour la plupart, toutes les réponses précédentes sont correctes, mais voici une version simplifiée de la logique avec visual & code (pour Python 3.7)
La logique est très simple, comme les autres, il a expliqué. Je vais créer Tortue/lent et le Lièvre rapide. Si nous passons deux pointeurs avec une vitesse différente, alors finalement rapide permettra de répondre à la lente !! vous pouvez aussi penser à ce que les deux coureurs dans un virement de bord circulaire de terrain. Si le fast runner continue à aller dans cercle puis il va rencontrer/passer le slow runner.
Donc, nous allons aller de l'Tortue/lent pointeur avec la vitesse de 1 à chaque itération, tandis que nous observons l'incrémentation ou de déplacer le Lièvre rapide/pointeur avec une vitesse de 2. Lorsqu'ils se rencontrent, nous savons qu'il existe un cycle. Ceci est également connu comme Floyd algorithme de recherche des cycles
Voici le code Python qui est-ce (avis has_cycle méthode est la partie principale):
Code suivant va trouver qu'il y a une boucle dans le SLL et si il y a, sera de retour alors nœud de départ.
Un autre O(n) solution.
Comme je l'ai vu la réponse sélectionnée, j'ai essayé un couple d'exemples et a constaté que:
Si (A1,B1), (A2,B2) ... (an, BN) sont les traversals de pointeurs A et B
lorsqu'Une des étapes 1 élément et B les étapes 2 éléments, et, Ai et Bj sont les nœuds traversés par A et B, et UN=BN.
Ensuite, le nœud à partir de l'endroit où la boucle commence est Ak, où k = floor(N/2).
ok - j'ai couru dans une interview hier - pas de matériaux de référence disponibles et je suis venu avec un de très différent de la réponse (tout en conduisant la maison, bien sûr...) étant donné que les listes chaînées sont NORMALEMENT (pas toujours, je le reconnais) alloués à l'aide de malloc logique, alors, nous savons que la granularité des allocations est connu. Sur la plupart des systèmes de ce est de 8 octets, ce qui signifie que le bas 3 bits sont toujours des zéros. Considérez - si l'on place la liste liée dans une classe de contrôle de l'accès et de l'utilisation d'un masque de 0x0E par un ou binaire dans la prochaine adresse, alors nous pouvons utiliser la partie inférieure de 3 bits pour stocker une pause de mie Ainsi, nous pouvons écrire une méthode qui vous permettra de stocker notre dernier fil d'ariane - dire 1 ou 2 et de les alterner. Notre méthode qui vérifie une boucle peut ensuite étape à travers chaque nœud (à l'aide de notre méthode suivante) et de vérifier si l'adresse suivante contient le courant du fil d'ariane - si elle ne nous avons une boucle - si ce n'est pas nous masquer la baisse de 3 bits et ajouter actuelle de notre fil d'ariane. Le fil d'ariane algorithme de vérification devrait être mono-thread que vous ne pourriez pas utiliser deux à la fois, mais il permettrait à d'autres threads pour accéder à la liste asynchrone - avec les mises en garde habituelles sur l'ajout/suppression de nœuds. Qu'en pensez-vous? Si d'autres personnes l'impression que c'est une solution valable, je peux écrire des exemples de la classe ... pense Juste que parfois, une nouvelle approche est la bonne et je suis toujours prêt à être dit que j'ai raté de peu le point... Merci à Tous de Marque
Une autre solution
La détection d'une Boucle:
Suppression de la boucle:
Une fois que nous détectons la boucle à l'Étape#3, jeu de nœud précédent de la prochaine valeur à NULL
#code
def detect_remove_loop(tête)
Tout d'abord, Créez un Nœud
Initialiser le pointeur de tête à l'échelle mondiale
Insérer des données dans la Liste Liée
Créer une fonction detectLoop()
Appel de la fonction main()
Une tout autre méthode:-
Inverser la liste chaînée.
En marche arrière si vous atteignez la tête à nouveau, puis il y a une boucle dans la liste,
si vous obtenez la valeur NULL alors il n'y a pas de boucle.
Le temps total de la complexité est O(n)