| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Двусвязный список. |
| Автор: andrew_121 12.4.2009, 18:28 | ||
| Всем доброго времени сУток! Вопрос в следующем. Есть двусвязный список:
Как(в теории) определить, закольцован он или нет? Рекурсия не подходит. Сами понимаете почему. В общем...любопытно Ваше мнение. Спасибо за внимание. |
| Автор: zim22 12.4.2009, 18:45 | ||
|
| Автор: mes 12.4.2009, 21:30 |
берешь два итератора("быстрый" и "медленный" ), пускаешь их по кругу, где на два шага "быстрого" приходится один шаг "медленного".. проверяешь оба итератора на равенство после каждого шага "быстрого", и если встретились раньше, чем "быстрый" дошел до конца, значит список закольцован. |
| Автор: Anikmar 12.4.2009, 21:31 |
| 100% результат - это создание массива указателей, в который помещать каждый узел и пробежаться по списку. Если такой адрес в массиве есть - значит закольцованность. Менее надежно - ввести в узлы служебное поле, которому присваивать определенное значение. Дошли до узла с таким значением - закольцован. Менее надежен потому, что случайно такое значение может быть. Для чистоты эксперимента прогнать второй раз с другим значением. |
| Автор: J0ker 13.4.2009, 00:17 |
для еще большей чистоты - прогнать третий раз потом четвертый потом пятый а потом доказывать начальству, что такого не может быть, что после пятого раза такой обломище ЗЫЖ к стенке надо таких прграммистов Добавлено через 2 минуты и 9 секунд 2mes, а я там давал вторую часть задачи? починить список? |
| Автор: Anikmar 13.4.2009, 07:30 |
Третий не нужно - для проверки 2-х раз достаточно За что меня к стенке? Злые вы. |
| Автор: Anikmar 13.4.2009, 09:44 | ||
А если конец списка ссылается на начало? Быстрый итератор будет равен первому элементу, а медленный в середине где-то? Разве равенство сработает?
Второй раз случайно может быть, но это обнаружимо. В любом случае, я вижу только мой первый вариант как 100% Все проникся - все равно догонит. Мудрые к стенке не ставят. Мудрые доводят до самоубийства. |
| Автор: mes 13.4.2009, 10:26 | ||
Предложенный мной вариант, был услышан некоторое время назад от Joker. припоминаю.. для односвязанного списка. Видится примерно такая картина: от места встречи проходим по круг у и узнаем длину петли. и на основании длины петли, кол-во шагов быстрого итератора, и шагов медленного можно посчитать место пересечения. Так для случая отн. большой петли (если быстрый до места встречи успел пройти по петле только раз) L=2*O-S , где L - длина от начала , до конца (до стыка который надо востанавливать) О-длина петли S-кол-во шагов медленного. Для остальной части задачи надо мозги напрячь.. попозже попробую.. |
| Автор: jonie 13.4.2009, 11:40 |
| имхо покрасить каждый элемент при простом проходе, если попали на покрашенное - значит кольцо есть. |
| Автор: mes 13.4.2009, 11:56 | ||
если только список предполагал возможность окрашивания + надо как то убедиться что список нигде не подкрашен. |
| Автор: andrew_121 13.4.2009, 12:58 | ||
Да. Этот вариант мне больше нравится. И вернулись к изначальному вопросу |
| Автор: jonie 13.4.2009, 13:17 |
| и в чем проблема создать map<void*, isColored> подобную структуру при обходе? не вижу никаких проблем. |
| Автор: andrew_121 13.4.2009, 13:21 |
| jonie, Да. Спасибо. Вопрос решен. |
| Автор: mes 13.4.2009, 14:46 | ||
а как узнать длину списка если он закольцован ? a если проверять есть ли в списке уже указатель, то зачем параметр isColored ? |
| Автор: andrew_121 13.4.2009, 15:20 |
| mes, Вы правы! Начал реализовывать, и уперся И так. Дисскусия продолжаеться. |
| Автор: mes 13.4.2009, 15:22 | ||
а чем не устраивает способ, где
? |
| Автор: andrew_121 13.4.2009, 15:27 |
| mes, Туплю по ходу |
| Автор: mes 13.4.2009, 16:35 | ||
вот набросок (работоспособность не проверял):
|
| Автор: J0ker 13.4.2009, 16:35 |
расстояние от точки встречи итераторов до точки пересечения всегда равно остатку от деления куска до пересечения на длину кольца т.е. простейший вариант пустить два "медленных" итератора - один из точки встречи, другой с начала списка - они встретятся в точке пересечения |
| Автор: mes 13.4.2009, 16:40 |
нда..самое эффективное решение как всегда лежит на поверхности J0ker, |
| Автор: jonie 14.4.2009, 09:20 | ||||
нечто вроде:
|
| Автор: mes 14.4.2009, 11:38 | ||
если Вы каждую элемент добавляете в карту, то а без него решение превращается в :
и требует наличие некого дополнительного объема памяти и также кол-во операций сравнения получается выше, чем у способа с двумя итераторами. ну вот и вопрос, зачем использовать заведомо медленный и не эффективный способ, строить дополнительные механизмы, когда все решается простым (двух-итераторным) обходом списка ? |
| Автор: jonie 14.4.2009, 12:16 |
| аа , я думал вы нашли там баг фатальный) |
| Автор: Dov 14.4.2009, 12:25 |
| andrew_121, ты покажи ф-цию вывода элементов списка, а потом можно будет говорить. Ты же выводишь элементы каким-то образом? Как ты это делаешь? По кругу или нет? |
| Автор: mes 14.4.2009, 12:53 | ||
Прежде чем выводить, тс. надо проверить не поврежден ли список, иначе прога войдет в бесконечный цикл |
| Автор: inside_pointer 14.4.2009, 23:38 | ||
можно сохранить prev и next в prevsave и nextsave и, продвигаясь по списку, проверять next на NULL и prevsave, а prev на NULL и nextsave |
| Автор: J0ker 15.4.2009, 00:28 | ||
| о блин толко щас заметил, что топик о двусвязном списке так тут все просто
Добавлено @ 00:33 двусвязный список может быть корректно закольцован только если хвост указывает на голову и наоборот все остальные случаи подпадают под термин "сломан" |
| Автор: andrew_121 15.4.2009, 10:38 | ||
Все остальные случаи должны корректно обрабатываться. Вот над этим и бьюсь сейчас. Нужно что-то вроди отчета, который потом(возможно однажды) придется использовать для "ремонта" списка. |
| Автор: inside_pointer 15.4.2009, 11:44 | ||
|
| Автор: mes 15.4.2009, 11:50 | ||
а где проверка, что cur->next не ноль ?! |
| Автор: inside_pointer 15.4.2009, 11:51 |
| я в процессе ещё |
| Автор: Dov 15.4.2009, 13:05 | ||
|
| Автор: mes 15.4.2009, 13:13 |
а зачем их делать членами класса ? |
| Автор: Dov 15.4.2009, 13:29 |
mes, вопрос, ведь, не в этом. Не хочешь - не делай. Это просто иллюстрация, примерчик, так сказать. Показано, как проверить и всё. Дальше, пусть человек сам думает. Добавлено через 3 минуты и 19 секунд там нужна ещё проверка "в обратную сторону", аналогичная этой.. |
| Автор: zim22 15.4.2009, 13:46 |
| Я так понимаю, это чтобы в консоли русский текст корректно отображался. Однако я встречал ещё два аналогичных варианта: 1) setlocale(LC_ALL, ""); 2) setlocale(LC_ALL, "Russian"); Интересно, сколько их всего... |
| Автор: mes 15.4.2009, 14:02 | ||
не хочу.. просто испугало.. представил, что эти строчки воспримут как руководство к действию. |
| Автор: Dov 15.4.2009, 14:08 | ||
гы-гы.... mes, зачем же о людях так думать? zim22, не знаю. На моём компе если так не сделать, то будет на иврите выводить... |
| Автор: mes 15.4.2009, 14:17 |
да после соседней темы с **(char *)&string еще и не такие ужасы привидятся.. |
| Автор: andrew_121 15.4.2009, 14:58 | ||
Это что? |
| Автор: zim22 15.4.2009, 15:14 |
извращение в чистом виде |