10042. LinkedList цикл
Задан
связный список. Содержит ли он цикл?
Определение
связного списка:
//Java
class ListNode {
int val;
ListNode
next;
ListNode(int x) {
val = x;
next = null;
}
}
// C++
class ListNode
{
public:
int val;
ListNode
*next;
ListNode(int x) :
val(x), next(NULL) {}
};
struct ListNode
{
int val;
struct ListNode* next;
};
Реализуйте
функцию hasCycle, которая
возвращает 1 если связный список содержит цикл и 0 иначе.
// Java
int hasCycle(ListNode head)
// C, C++
int hasCycle(ListNode *head)
Пример
Функция hasCycle возвращает 0, так
как связный список не содержит цикл.
Функция hasCycle возвращает 1, так
как связный список содержит цикл.
связный
список
Воспользуемся двумя
указателями p и q, двигая их по принципу малого и большого шага. Сначала установим
их на начало списка. Далее итеративно двигаем первый указатель p вперед на одну позицию по списку, а
второй q – на две позиции.
Останавливаемся, если:
·
один из указателей (это будет указатель q) достиг конца списка. Тогда список не
является циклическим.
·
оба указателя указывают на один элемент. Это значит, что
быстрый указатель q догнал медленный p, и список содержит цикл.
На третьей итерации указатель q догнал
p, оба указателя указывают на вершину
со значением 4. Цикл существует.
Реализация алгоритма
int hasCycle(ListNode *head)
{
if (head == NULL) return 0;
Устанавливаем указатели p и q на начало списка.
ListNode* p =
head;
ListNode* q =
head;
Пока за указателем q имеется хотя бы два
элемента (быстрый указатель можно двигать на два шага вперед), продолжаем цикл.
while
(q->next && q->next->next)
{
p =
p->next;
q =
q->next->next;
Если указатели равны, то они указывают на одну и ту же ячейку памяти.
Быстрый указатель q догнал медленный p, список содержит цикл.
if (p
== q) return 1;
}
Цикла нет, возвращаем 0.
return 0;
}
Java реализация
int
hasCycle(ListNode head)
{
if (head == null) return 0;
ListNode p = head;
ListNode q = head;
while (q.next != null && q.next.next != null)
{
p = p.next;
q = q.next.next;
if (p == q) return 1;
}
return 0;
}