Вы несколько перегибаете палку ...
Просто упростите свой код до минимума, и вы получите то, что вам нужно ... например:
find_cycle(G,Vs) :-
member(V-_Edges,G), % don't care about starting point
find_cycle(G,V,[],Vs).
find_cycle(_G,V,SeenVs,[V|SeenVs]) :-
memberchk(V,SeenVs).
find_cycle(G,V,SeenVs,Cycle) :-
\+memberchk(V,SeenVs),
member(V-Es,G),
member(Ve,Es),
find_cycle(G,Ve,[V|SeenVs],Cycle).
?- G=[a-[b,c],b-[a,c],c-[]],find_cycle(G,C).
G = [a-[b, c], b-[a, c], c-[]],
C = [a, b, a] ;
G = [a-[b, c], b-[a, c], c-[]],
C = [b, a, b] ;
false.
Или, чтобы избежать дублирования поиска в списке посещенных ребер:
find_cycle(G,V,SeenVs,Cycle) :-
( memberchk(V,SeenVs)
-> Cycle=[V|SeenVs]
; member(V-Es,G),
member(Ve,Es),
find_cycle(G,Ve,[V|SeenVs],Cycle)
).
редактировать после комментария ...
Для эффективности, обратите внимание, я использовал memberchk / 2 в тест, а не член / 2. Реализация в SWI-Prolog очень быстрая, так как использует низкоуровневое представление списков (skip list
), выполненное в C. Итак, у вас должны быть очень длинные списки, прежде чем вы начнете наблюдать некоторые улучшения с использованием какой-либо другой структуры данных (есть такие ... как rbtrees, avltrees, ...). Но если ваши списки такие большие, то нужно улучшить весь алгоритм. Опять же, они есть, вы можете начать поиск в библиотеке ( ugraph ).