LINUX.ORG.RU

Проверка, что список закольцован

 ,


1

2

В голове вертится только два алгоритма:
1. Попытаться измерить длину - если при вычислении счетчик опрокинулся - то список кольцевой.
2. При чтении завести массив адресов, в который вносить прочитанные адреса, а затем при прочитывании каждого следующего пытаться искать его в массиве.

Есть канонiчный метод?

★★

Последнее исправление: sambist (всего исправлений: 1)
Ответ на: комментарий от crowbar

A -> B -> C -> D -> B

Так что не сработает.

sambist ★★
() автор топика

Воткни в структуру флаг "seen", скажем, так:

typedef struct __list_item{
  struct __list_item *prev;
  struct __list_item *next;
  sometype data;
  uint64_t flags;
...
} list_item;

#define FLAG_SEEN    1 << 0
#define FLAG_UNUSED  1 << 1
...
#define SOME_FLAG    1 << 63

далее при просмотре списка тебе придется проходиться по нему 2 раза: 1-й раз для обнуления FLAG_SEEN:

list_foreach_clear_flag(my_list, FLAG_SEEN); // понятно, что если возможна закольцованность, придется еще и содержать массив со списком членов списка
и второй раз — устанавливая флаги:
list_item *itm = my_list;
do{
  if(itm->flags & FLAG_SEEN) break; // itm->prev будет указывать на последний член кольца
  itm->flags |= FLAG_SEEN;
}while((itm = itm->next));

но намучишься ты с таким списком изрядно!

Eddy_Em ☆☆☆☆☆
()

Попытаться измерить длину - если при вычислении счетчик опрокинулся

счетчик 1-байтовый, или 8-байтовый?

MyTrooName ★★★★★
()

При чтении завести массив адресов, в который вносить прочитанные адреса, а затем при прочитывании каждого следующего пытаться искать его в массиве.

лучше не в массив, а в хеш

MyTrooName ★★★★★
()
Ответ на: комментарий от MyTrooName

Этот способ подходит, если эмпирически известна максимально возможная длина списка и она не слишком большая. Тогда и переполнения ждать не надо.

alegz ★★★★
()

пустить 2 счетчика, один идёт поочередно, другой - через один. Если счетчики встретятся, то цикл.

qnikst ★★★★★
()
Ответ на: комментарий от qnikst

`1 -> 2 -> 3 -> 2 -> ..` — имхо попадает под определение закольцован.

Ты и ТС почему-то называете кольцом то, что является графом с циклом. Хотя... понятно, почему.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

ну к алгебраической структуре с операциями обратимного сложения и умножения это явно не относится. Так же раз разговор про список, то имеется ввиду структура данных double/single linked list. Граф это «модель» описывающая данную стуктуру данных. Так что иди умничай в другой тред, пожалуйста, тем более у тебя это не очень получается. Спасибо.

qnikst ★★★★★
()
Ответ на: комментарий от qnikst

ну к алгебраической структуре с операциями обратимного сложения и умножения это явно не относится. Так же раз разговор про список, то имеется ввиду структура данных double/single linked list.

Именно так. И «кольцевым списком» обычно называется вот это:

Circular list

In the last node of a list, the link field often contains a null reference, a special value used to indicate the lack of further nodes. A less common convention is to make it point to the first node of the list; in that case the list is said to be 'circular' or 'circularly linked'

Так что иди умничай в другой тред, пожалуйста

Ответ ТС уже дан, умничаешь ты, спасибо.

tailgunner ★★★★★
()

Есть веселый метод решить эту задачу - если идти и менять направление списка на противоположное, то в коце концов вернешся в начало.

dizza ★★★★★
()
Ответ на: комментарий от Eddy_Em

На первом проходе нельзя определить, когда нужно остановиться. Если хранить множество всех посещённых вершин, то смысла делать два прохода нету.

kvap
()
Ответ на: комментарий от kvap

Читай комментарий:

придется еще и содержать массив со списком членов списка

В принципе, можно и так сделать: изначально этот флаг держать нулевым, а при проверке на закольцованность после выявления закольцованности/незакольцованности опять вернуться к началу списка и пройтись, сбрасывая флаг.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Я о том, что для решения исходной задачи, мы делаем два прохода. Но чтобы закончить первый проход, нужно решить, по сути, ту же задачу...

kvap
()

google://задача про зайца и черепаху

KennyMinigun ★★★★★
()
Ответ на: комментарий от Eddy_Em

Что-то вроде

list_item *itm = my_list, *circle_start = NULL;
do{
  if(itm->flags & FLAG_SEEN){
    circle_start = itm;
    break;
  }
  itm->flags |= FLAG_SEEN;
}while((itm = itm->next));
do{itm->flags &= ~FLAG_SEEN;}while((itm = itm->prev));

В итоге если есть закольцованность, circle_start будет указывать на один из членов кольца. Если нет — будет NULL.

Если нужно лишь диагностировать закольцованность и пофиг на лишние операции, можно сделать так: хранить в списке еще и общее количество членов, N. Затем пройтись по списку N-1 раз: itm = itm->next. Если у последнего itm->next будет !NULL, список точно закольцован!

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

А чтобы изначально сбросить у всех элементов FLAG_SEEN, нужно сделать проход. Который не закончится из-за цикла! А если мы сделали, чтобы он заканчивался, то значит задача уже решена, и мы придумали бесполезный алгоритм.

kvap
()
Ответ на: комментарий от kvap

Не нужно: calloc сразу сделает с пустыми флагами, когда будешь очередной элемент в список добавлять.

Проблема надумана.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Твое решение требует модификации изначальной структуры данных. Есть более чистое решение.

dizza ★★★★★
()

Решение называется алгоритм Госпера, в гугле есть, или например в Алгоритмических трюках для программистов Уоррена.

anonymous
()
Ответ на: комментарий от anonymous

Вообще, задачу решали много кто - Флойд, Кнут, Брент, Седжвик, Шиманский, Ниваш - и опубликовали результаты, а вот про алгоритм Госпера мало известно, хотя он довольно эффективный.

anonymous
()
Ответ на: комментарий от anonymous

Без модификации элементов последовательности/списка это не очень простая задача.

anonymous
()
Ответ на: комментарий от qnikst

Это кстати, алгоритм Флойда. Он находит такое n, при котором a[n]=a[2n]. Если это произошло, то период T есть, и он делит n.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.