4 / 1 / 0
Регистрация: 09.10.2015
Сообщений: 204
|
||||||
1 | ||||||
Сортировка слиянием кольцевого списка23.10.2016, 23:37. Показов 2767. Ответов 20
Метки нет (Все метки)
Есть класс двусвязного кольцевого списка и итератор к нему-шаблоны.
не могу довести до ума сортировку слиянием для этого списка и понять в чем проблема(( //tail->next=первый //tail->prev=последний //tail-узел ограничитель.в поле val-лежит мусор
0
|
23.10.2016, 23:37 | |
Ответы с готовыми решениями:
20
Сортировка кольцевого двусвязного списка (пузырьковая) Сортировка линейного списка слиянием сверху вниз Шаблон однонаправленного кольцевого списка Создание кольцевого однонаправленного списка |
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
|
|
24.10.2016, 00:00 | 2 |
Kristina_S, раз взялась делать итераторы, то ими и пользуйся.
Реализуй сортировку слиянием, которая работает для любой пары итераторов (будь то итераторы из std::vector или другие). Затем поправь свой итератор так, что бы он работал с твоей сортировкой.
0
|
4 / 1 / 0
Регистрация: 09.10.2015
Сообщений: 204
|
|
24.10.2016, 00:05 [ТС] | 3 |
с итераторами все хорошо.да и алгоритм сортировки я понимаю прекрасно и код написала внятный.просто там ошибка времени выполнения и я не знаю как ее убрать
0
|
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
|
||||||
24.10.2016, 00:32 | 4 | |||||
Ну не надо. В твоей сортировке с жонглированием указателями в итераторах черт ногу сломит.
Предлагаю первым делом разобраться, почему вот в этом примере
0
|
4 / 1 / 0
Регистрация: 09.10.2015
Сообщений: 204
|
|
24.10.2016, 00:45 [ТС] | 5 |
хм,я так понимаю у меня середина как-то неправильно находится? или не в этом дело?
0
|
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
|
|
24.10.2016, 00:57 | 6 |
Kristina_S, я думаю, что дело в твоих адовых указателях.
Меняешь например начальный узел с конечным во время сортировки и все. Начало в конце, конец в начале, где новый конец, а где начало, куда дальше двигаться - непонятно. Ты забыла одну небольшую вещь - ты должна сортировать значения внутри узлов, а не сами узлы. Попробуй переписать свою сортировку так, что бы ни разу не обращаться к iterator::node (обращаясь только к публичным методам).
0
|
4 / 1 / 0
Регистрация: 09.10.2015
Сообщений: 204
|
|
24.10.2016, 01:31 [ТС] | 7 |
я не понимаю логики,мне казалось что без буфера сортировать можно если перенаправлять указатели а не переписывать сами значения в узлах. можешь хотя бы на псевдокоде показать что и как?
Добавлено через 2 минуты проблема кроется в merge или merse_sort_rec?
0
|
Вездепух
11696 / 6375 / 1724
Регистрация: 18.10.2014
Сообщений: 16,078
|
|
24.10.2016, 01:38 | 8 |
Наоборот, скорее всего цель всего этого - именно в сортировке самих узлов путем исправления ссылок. Т.е. это аналог
std::list<>::sort .
0
|
4 / 1 / 0
Регистрация: 09.10.2015
Сообщений: 204
|
||||||
24.10.2016, 01:39 [ТС] | 9 | |||||
0
|
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
|
|
24.10.2016, 01:49 | 10 |
Kristina_S,
Можно. К тому же сортировку слиянием и так можно реализовать без использования дополнительного буфера, об этом можно почитать в третьем томе Кнута. В merge я так думаю. Не могу, ибо не знаю как. Я не хочу придумывать на ходу алгоритм сортировки циклического списка... Можешь попробовать перед сортировкой разорвать цикл в списке, отсортировать, а потом опять зациклить. Будет чуть проще.
0
|
4 / 1 / 0
Регистрация: 09.10.2015
Сообщений: 204
|
|
24.10.2016, 01:52 [ТС] | 11 |
ясно.спасибо за дельные советы
0
|
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
|
|
24.10.2016, 02:11 | 12 |
Может быть и так. Кстати, заглянул в исходники, в std::list как раз под капотом такой merge sort и сидит.
0
|
Вездепух
11696 / 6375 / 1724
Регистрация: 18.10.2014
Сообщений: 16,078
|
|
24.10.2016, 02:23 | 13 |
На данном тестовом примере проблема, разумеется, в
merge , ибо в данном примере никто, кроме merge , никакой фактической работы не делает.Однако стоит заметить, что данная реализация сортировки практической ценности не представляет. Вся идея сортировки списка заключается в том, что она не требует прямого (индескного) доступа и аналогичных операций. Поэтому ни о каком int we_need = last - first; и iterator mid = first + sz / 2; в грамотно реализованной сортировке списка речи быть не может. То есть никаких пробеганий по списку с целью подсчета элементов или с целью поиска i-того элемента быть не должно. Даже у итератора не должно быть операций + и - . Такие операции есть только у random access iterator. У вас же - bidirectional iterator, который сам по себе в принципе не должен поддерживать + и - .Для реализации merge sort на списке не надо прыгать на средний элемент. Это в массивах так делают. В списке можно прекрасно обойтись без этого. Именно так. Причем там сидит именно грамотно реализованный merge sort, который ни в коем случае не будет пытаться эмулировать random access iterators на основе итераторов списка.
0
|
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
|
|
24.10.2016, 02:25 | 14 |
Хоть внутри итератора этого быть и не должно, но середину то мы как-то отыскать должны?
Значит нам нужен и размер списка, и возможность от начала добраться до середины. Добавлено через 1 минуту Смысл в сортировке слиянием, если она "не умеет" разбивать контейнер на две половинки?
0
|
Вездепух
11696 / 6375 / 1724
Регистрация: 18.10.2014
Сообщений: 16,078
|
|
24.10.2016, 02:40 | 15 |
Реализовывать алгоритм merge sort на списке по принципу "сверху-вниз", т.е. периодическим итеративным беганьем по списку для поиска середины - это детский сад. Список не поддерживает прямого доступа, по каковой причине стратегию "сверху-вниз" к нему осмысленно применить не получится.
Списки сортируют merge sort по стратегии "снизу-вверх" (https://en.wikipedia.org/wiki/... sing_lists), где совершенно не требуется заниматься подобной ерундой. Добавлено через 2 минуты Например, реализация в GCC (https://gcc.gnu.org/onlinedocs... tml#l00355) работает именно снизу-вверх, как и реализация в MSVC. Добавлено через 7 минут Сортировка слиянием на списке разбивает список на половинки, но по совсем другому принципу: 1. Мы считаем, что одна половинка - это четные элементы, а другая - нечетные. Идя слева-направо, делаем попарное слияние одноэлементных списков в списки длины 2. 2. Теперь считаем, что одна половинка - это четные списки длины 2, а другая - нечетные списки длины 2. Идя слева-направо, делаем попарное слияние таких списков в списки длины 4. 2. Теперь считаем, что одна половинка - это четные списки длины 4, а другая - нечетные списки длины 4. Идя слева-направо, делаем попарное слияние таких списков в списки длины 8. И т.д. И всю эту обработку можно аккуратно выполнить за один проход исходного списка слева-направо (разумеется, не за O(n), ибо при слиянии подсписков их придется перепроходить снова). Другими словами, половинки есть и в этом случае. Но они получаются не путем разрезания списка посередине, а путем рассмотрения списка как двух гребенок, вложенных одна в другую зубьями.
0
|
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
|
|||||||||||
24.10.2016, 02:43 | 16 | ||||||||||
Понятно, спасибо.
Тут я не соглашусь, вот свежевыдернутые исходники из MSVC: Кликните здесь для просмотра всего текста
Волшебная строчка оттуда:
1
|
Вездепух
11696 / 6375 / 1724
Регистрация: 18.10.2014
Сообщений: 16,078
|
|
24.10.2016, 02:53 | 17 |
Это интересная тема. Я хорошо помню, что во времена Dinkumware-вской реализации стандартной библиотеки MSVC использовал тот же алгоритм "onion chaining", что виден по ссылке для GCC.
Вполне может быть, что, к моему удивлению, эти реализации не отличаются по производительности. При этом в лоб используется рекурсия! Странно... (Ну, по крайней мере, они хоть не перевычисляют длину списка заново на каждом уровне слияния.)
0
|
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
|
|
24.10.2016, 03:00 | 18 |
Быстренько проверил у себя:
VS2010/13 - реализация схожа с GCC. VS2015 - именно его я кидал выше.
0
|
Вездепух
11696 / 6375 / 1724
Регистрация: 18.10.2014
Сообщений: 16,078
|
|
24.10.2016, 03:03 | 19 |
Это фактически требование C++11, который теперь настаивает на том, чтобы
std::list<>::size() выполнялся за O(1).GCC, кстати, отказался соблюдать это требование стандарта и не хранит размер (т.е. его std::list<>::size() выполняется за O(n), вопреки требованиям стандарта).Понятно, что наличие хранимого размера делает данный алгоритм более привлекательным, но меня все равно меня смущает iterator _Mid = _STD next(_First, _Size / 2); . Неужели оно стоит того?
0
|
4 / 1 / 0
Регистрация: 09.10.2015
Сообщений: 204
|
|
24.10.2016, 12:05 [ТС] | 20 |
так мне кто нибудь поможет кодом ,ребята?
0
|
24.10.2016, 12:05 | |
24.10.2016, 12:05 | |
Помогаю со студенческими работами здесь
20
Реализация кольцевого списка на СТЛ Нахождение и изменение элемента двунаправленного кольцевого списка Консольный интерфейс для кольцевого односвязного списка Сортировка слиянием. В каком куске кода происходит сортировка и каким именно образом? Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |