Страница 1 из 2

Замена порядка узлов в списке обратным.

Добавлено: 09 мар 2010, 13:57
Dragon
Есть неотсортированный связный список целых чисел. Надо заменить порядок узлов обратным. Создавать и удалять узлы нельзя.

Если бы можно было создавать узлы, то согласно правилу стека (FILO), узлы нового списка после поузельного копирования были бы упорядочены как надо.

Долго ломал голову и пришел к следующему алгоритму.
Вид узла списка:
struct Node
{
int value;
Node *link;
};
typedef Node* NodePtr;

Список:
NodePtr head;
...

Необходимы следующие указатели на список:
- start = head; - первый элемент списка
- before_end = head; - предпоследний элемент списка
- end = NULL; - конец списка
- iter - для прохождения через список циклом for

Переменная для пузырьковой сортировки:
int temp;

Код: Выделить всё

for(iter = head; iter != end; iter = iter->link) //проходим по всему списку
{
before_end = before_end->link;
}

//По окончанию прохождения по списку, before_end, теоретически, должен указывать на предпоследний элемент
//но почему-то он проскакивает дальше

//Меняем значения первого и последнего элементов списка местами
temp = start->value;
start->value = iter->value;
iter->value = temp;

start = start->link; //следующий не упорядоченный элемент
end = before_end; //предыдущий неупорядоченный элемент
before_end = start; //поиск предпоследнего элемента
Повторять это до тех пор, пока список не будет упорядочен.
Условия окончания упорядочивания приблизительно представляю:
- прогонять цикл, пока после последних 3 строк before_end == end.

Но проверка алгоритма срывается после первого цикла for. Если список представляет из себя: 1 3 2 5 4, то во время цикла before_end указывает на 3 2 5 4 и выскакивает за пределы списка, завершая программу ошибкой.

Что не так работает? Корректен ли алгоритм или есть проще варианты?

Re: Замена порядка узлов в списке обратным.

Добавлено: 09 мар 2010, 14:18
Albor
Dragon писал(а):Есть неотсортированный связный список целых чисел. Надо заменить порядок узлов обратным. Создавать и удалять узлы нельзя.
Разве в задании говорится о сортировке? По-моему, всё что нужно - это хвост списка сделать головой и изменить ссылки так, чтобы список остался списком.

Re: Замена порядка узлов в списке обратным.

Добавлено: 09 мар 2010, 14:39
Dragon
Я в списках еще не очень свободно плаваю, зависаю, но разве в связном списке не только в одну сторону идти можно?
Или имеется в виду создать новый список в который перенести данные по принципу стека (FILO):

Код: Выделить всё

void insert_node(NodePtr& head, int the_number)
{
    NodePtr temp;
    temp = new Node;
    temp->value = the_number;
    temp->link = head;
    head = temp;
}

void reverse(NodePtr& head)
{
    NodePtr iter, temp;

    for(iter=head; iter != NULL; iter = iter->link)
    {
        insert_node(temp, iter->value);
    }

    head = temp;
}
Хотя если подумать, то создание буферного списка - не является "созданием/удалением узлов". Или тоже не то?

Re: Замена порядка узлов в списке обратным.

Добавлено: 09 мар 2010, 15:24
Albor
С чего ты взял что нужно создавать что-то новое. Вссё что нужно - это переписать в узлах имеющегося списка значение указателей

Re: Замена порядка узлов в списке обратным.

Добавлено: 09 мар 2010, 18:18
Romeo
Эта операция называется реверсом списка. Для выполнения её достаточно пройтись по списку однократно (линейная сложность). Перевыделения памяти не требуются. Для алгоритма нужны всего две вспомогательные переменные.

На каждой итерации в отдельной переменной должен быть сохранён адрес "следующего" элемента, затем ссылка должна быть перенаправлена в предыдущий элемент (взятый из второй временной переменной), затем следует перезаписать переменную, хранящую пред. элемент адресом текущего элемента, затем мы должны перейти к следующем элементу и выполнить ту же самую последовательность действий снова.

Re: Замена порядка узлов в списке обратным.

Добавлено: 10 мар 2010, 11:52
Dragon
Хм, надо будет попробовать сделать так (на первый взгляд замудрено сильно).
Значит мой вариант перепаковки списка не годится вообще?

Хотя в стандартной библиотеке видел класс List в котором есть функция reverse. Правда как она работает не смотрел, но похоже именно так, как вы и пишете (создание буферного списка - лишняя нагрузка на память).

Re: Замена порядка узлов в списке обратным.

Добавлено: 26 авг 2010, 17:52
licenok

Код: Выделить всё

//дорабатываем немножко структуру
struct Node
{
int value;
Node *linkPrev; // предыдущий элемент
Node *linkNext; // последующий элемент
// NULL - если нет Node (это встречается в голове и хвосте)
};

void MovPrev(Node* nd) // перетаскивание элемента на 1 позицию в направлении хвоста
{
  if (nd == head) head = nd->linkPrev;
  if (nd->linkNext) nd->linkNext->linkPrev = nd->linkPrev;
  if (nd->linkPrev) nd->linkPrev->linkNext = nd->linkNext;
  Node* prev = NULL;
  if (nd->linkPrev) prev = nd->linkPrev->linkPrev;
  if (nd->linkPrev) nd->linkPrev->linkPrev = nd;
  nd->linkNext = nd->linkPrev;
  nd->linkPrev = prev;
}

int count = количество всех элементов списка ;


for (int i=count-1 ; i>0; i--)
{
  Node* nd = head; // берём голову
  for (int j=0; j<i; j++) MovPrev(nd); // и тащим её в хвост
}

// собственно всё ..

Re: Замена порядка узлов в списке обратным.

Добавлено: 26 авг 2010, 17:57
rrrFer
не по теме:
хотите перерешать все задачи? :)

Re: Замена порядка узлов в списке обратным.

Добавлено: 26 авг 2010, 18:32
licenok
вдруг кому-нибудь пригодится ?

Re: Замена порядка узлов в списке обратным.

Добавлено: 27 авг 2010, 13:33
Romeo
Между прочим очень похвально :) Только таги code используй, плиз.