Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Удаления значения в списку. Бага 
:(
    Опции темы
sswt
Дата 28.10.2015, 12:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 41
Регистрация: 22.9.2015

Репутация: нет
Всего: нет



У меня проблема:  когда я вывожу  значения printBackward  послу удаления головы или следущего значения у меня бага сплывает, printForward нормально выводит  подскажите  где ошибка. Тоесть когда я с хвоста начинаю читать  бага появляеться
Код
void RemoveFirst(DoublyLinkedList* list)
{
    DoublyLinkedList::Node* temp = list->head;
    list->head = temp->nextNode;
    list->head->prevNode = nullptr;
    free(temp);

}

void RemoveAfter(DoublyLinkedList::Node* node)
{
    DoublyLinkedList::Node* temp = node->nextNode;
    node->nextNode = temp->nextNode;
    free(temp);
}
void PrintForward(const DoublyLinkedList* list)
{
    for (DoublyLinkedList::Node* node = list->head; node != nullptr; node = node->nextNode)
        printf("%d\n", node->value);
    printf("\n");
}
void PrintBackward(const DoublyLinkedList* list)
{
    for (DoublyLinkedList::Node* node = list->tail; node != nullptr; node = node->prevNode)
        printf("%d\n", node->value);
    printf("\n");
}
int main()
{
RemoveFirst(list);
    PrintForward(list);
    PrintBackward(list);

    RemoveAfter(list->head);
    PrintForward(list);
    PrintBackward(list);
return 0;
}


PM MAIL   Вверх
math64
Дата 28.10.2015, 12:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 12
Всего: 72



При удалении элементов RemoveFirst и RemoveAfter не проверяешь, пустой ли список.
Нужно также проверить, удаляется ли последний элемент и поправить list->tail если нужно.
PM   Вверх
sswt
Дата 28.10.2015, 13:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 41
Регистрация: 22.9.2015

Репутация: нет
Всего: нет



math64
Код
 все равно не пашет
void RemoveFirst(DoublyLinkedList* list)
{
    if (list->head == nullptr) 
    {
        break;
    }
    DoublyLinkedList::Node* temp = list->head;
    list->head = temp->nextNode;
    list->head->prevNode = nullptr;
    if (temp == list->tail) {
        list->tail = nullptr;
    }
    free(temp);
};
}


Это сообщение отредактировал(а) sswt - 28.10.2015, 13:11
PM MAIL   Вверх
feodorv
Дата 28.10.2015, 13:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(sswt @  28.10.2015,  12:38 Найти цитируемый пост)
printForward нормально выводит

Так намёк же - посмотреть, где не правится значение prevNode. Ну, вот здесь правится:
Цитата(sswt @  28.10.2015,  12:38 Найти цитируемый пост)
void RemoveFirst(DoublyLinkedList* list)
{
    DoublyLinkedList::Node* temp = list->head;
    list->head = temp->nextNode;
    list->head->prevNode = nullptr;
    free(temp);
}

А здесь вообще никак:
Цитата(sswt @  28.10.2015,  12:38 Найти цитируемый пост)
void RemoveAfter(DoublyLinkedList::Node* node)
{
    DoublyLinkedList::Node* temp = node->nextNode;
    node->nextNode = temp->nextNode;
    free(temp);
}
Где изменение значения node->nextNode->prevNode? Про, то что node->nextNode может быть nullptr, я даже не намекаю.

Это сообщение отредактировал(а) feodorv - 28.10.2015, 13:30


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
sswt
Дата 28.10.2015, 13:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 41
Регистрация: 22.9.2015

Репутация: нет
Всего: нет



feodorv, можете написать как нужно для RemoveFirst, а то я запуталась немножко(((
PM MAIL   Вверх
math64
Дата 28.10.2015, 13:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 12
Всего: 72



Не break, а return.
Прежде, чем делать list->head->prevNode = nullptr; нужно проверить  list->head != nullptr;
Аналогичные изменения в RemoveAfter.
Возможны ошибки в невыложенной части кода.

Добавлено через 7 минут и 7 секунд
Цитата(sswt @  28.10.2015,  13:25 Найти цитируемый пост)
можете написать как нужно для RemoveFirst, а то я запуталась немножко((( 

Код

void RemoveFirst(DoublyLinkedList* list)
{
    if (list == nullptr) // списка нет
        return;
    DoublyLinkedList::Node* temp = list->head;
    if (temp == nullptr) // список пуст
        return;
    list->head = temp->nextNode;
    if (list->head != nullptr) // в списке ещё что-то осталось
        list->head->prevNode = nullptr;
    else // список стал пустым
        list->tail = nullptr;
    free(temp);
}

PM   Вверх
sswt
Дата 28.10.2015, 13:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 41
Регистрация: 22.9.2015

Репутация: нет
Всего: нет



math64,  не помогло(
PM MAIL   Вверх
feodorv
Дата 28.10.2015, 13:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(sswt @  28.10.2015,  13:25 Найти цитируемый пост)
feodorv, можете написать как нужно для RemoveFirst, а то я запуталась немножко((( 

Думаю, как-то так:
Код

void RemoveAfter(DoublyLinkedList::Node* node)
{
    if( node == nullptr || node->nextNode == nullptr ) return;
    DoublyLinkedList::Node* temp = node->nextNode;
    node->nextNode = temp->nextNode;
    if( node->nextNode != nullptr )
      node->nextNode->prevNode = node;
    else 
      tail = node;
    free(temp);
}



--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
sswt
Дата 28.10.2015, 13:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 41
Регистрация: 22.9.2015

Репутация: нет
Всего: нет



feodorv, спасибо

Добавлено через 2 минуты и 24 секунды
feodorv,  у нас тут list нету, 
откуда вы берету переменую tail = node; ????
PM MAIL   Вверх
feodorv
Дата 28.10.2015, 13:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(sswt @  28.10.2015,  13:36 Найти цитируемый пост)
feodorv,  у нас тут list нету, 
откуда вы берету переменую tail = node; ???? 

Ааааа. А я было подумал, что:
Код

void DoublyLinkedList::RemoveAfter(DoublyLinkedList::Node* node)
{
  ...
}

А так-то да, лист в аргументы добавить придётся. А если у Вас там ещё head и tail приватные, то придётся браться за голову)))


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
math64
Дата 28.10.2015, 14:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 12
Всего: 72



Либо 1) RemoveAfter(DoublyLinkedList::Node* node) будет методом класса DoublyLinkedList,
либо 2) в DoublyLinkedList::Node нужно добавить поле DoublyLinkedList* list,
либо 3) нужно добавить параметр в RemoveAfter(DoublyLinkedList* list, DoublyLinkedList::Node* node);
Лучше сделать 1) и 2) одновременно и добавить проверку, что node принадлежит нужному списку.

PM   Вверх
sswt
Дата 28.10.2015, 15:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 41
Регистрация: 22.9.2015

Репутация: нет
Всего: нет



math64
Код

oid RemoveFirst(DoublyLinkedList* list)
{
    DoublyLinkedList::Node* firstNode = list->head;
    DoublyLinkedList::Node* secondNode = firstNode->nextNode;
    if (secondNode != nullptr)
        secondNode->prevNode = nullptr;
    else
        list->tail = nullptr;
    list->head = secondNode;
    free(firstNode);
}

void RemoveAfter(DoublyLinkedList* list, DoublyLinkedList::Node* node)
{
    DoublyLinkedList::Node* firstNode = node->nextNode;
    DoublyLinkedList::Node* secondNode = firstNode->nextNode;
    node->nextNode = firstNode->nextNode;
    if (node->nextNode != nullptr)
        node->nextNode->prevNode = node;
    else
        list->tail = node;
    free(firstNode);
}

PM MAIL   Вверх
math64
Дата 28.10.2015, 16:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 12
Всего: 72



В обоих случаях нужна проверка firstNode != nullptr.
В RemoveAfter ты заводишь secondNode, но нигде его не используешь (можно сделать как в RemoveFirst).
list != nullptr можешь проверять, а можешь нет - если это гарантировано при вызове.

Добавлено через 4 минуты и 51 секунду
Кстати можно сделать
Код

void RemoveFirst(DoublyLinkedList* list)
{
    RemoveAfter(list, nullptr);
}

и проверять в RemoveAfter на node == nullptr - в этом случае удалять первый элемент списка, код получается похожим.
К сожалению, в RemoveAfter нет контроля, что node принадлежит нужному списку.
PM   Вверх
sswt
Дата 28.10.2015, 16:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 41
Регистрация: 22.9.2015

Репутация: нет
Всего: нет



math64, так ?  та нет лутче поддельности 2 функции  делать
Код

void RemoveAfter(DoublyLinkedList* list, DoublyLinkedList::Node* node)
{
    DoublyLinkedList::Node* firstNode = node->nextNode;
    DoublyLinkedList::Node* secondNode = firstNode->nextNode;
    
    if (firstNode != nullptr)
        secondNode->prevNode = node;
    else
        list->tail = node;
    free(firstNode);
}

PM MAIL   Вверх
feodorv
Дата 28.10.2015, 16:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(sswt @  28.10.2015,  16:45 Найти цитируемый пост)
    DoublyLinkedList::Node* secondNode = firstNode->nextNode;
    
    if (firstNode != nullptr)

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

Добавлено через 7 минут и 33 секунды
Вообще, вся логика по проверке на нулевые указатели нарушена полностью (заодно и логика алгоритма). secondNode тоже может быть нулевым указателем, тогда делать secondNode->prevNode никак нельзя. Если уж Вам так не нравится конструкция node->nextNode->prevNode, то реализовывайте её последовательно:
Код

void RemoveAfter(DoublyLinkedList* list, DoublyLinkedList::Node* node)
{
    DoublyLinkedList::Node* firstNode = node->nextNode;

    if( firstNode != nullptr )
    {
        DoublyLinkedList::Node* secondNode = firstNode->nextNode;
    
        if (secondNode != nullptr) //// not firstNode!!!!
            secondNode->prevNode = node;
        else
            list->tail = node;

        free(firstNode);
    }
}



--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
sswt
Дата 28.10.2015, 17:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 41
Регистрация: 22.9.2015

Репутация: нет
Всего: нет



feodorv
Код

void RemoveAfter(DoublyLinkedList* list, DoublyLinkedList::Node* node)
{
    DoublyLinkedList::Node* firstNode = node->nextNode;
    DoublyLinkedList::Node* secondNode = firstNode->nextNode;
    
    if (firstNode != nullptr)
    {
        DoublyLinkedList::Node* secondNode = firstNode->nextNode;
        secondNode->prevNode = node;
    }
    else
        list->tail = node;
    free(firstNode);
}

как то так, я уже  запуталась, поэтому  если  дурню пишу извините)
PM MAIL   Вверх
feodorv
Дата 28.10.2015, 17:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



И жутко не нравится это free(). Почему не new+delete?

Добавлено через 4 минуты и 19 секунд
Цитата(sswt @  28.10.2015,  17:06 Найти цитируемый пост)
если  дурню пишу извините) 

Дурните. Я Вам привел правильный и лаконичный вариант. Почему бы не подумать над ним хоть немножко? Зачем Вы опять разименовываете firstNode до проверки? Почему не проверяете secondNode на nullptr? Почему делаете
Цитата(sswt @  28.10.2015,  17:06 Найти цитируемый пост)
list->tail = node;
в случае, когда нулевой firstNode (а в этом случае вообще ничего делать не нужно - с Вас объяснение, почему так)????????????????????????????????????????????????????????????????????????????????



--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
sswt
Дата 28.10.2015, 17:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 41
Регистрация: 22.9.2015

Репутация: нет
Всего: нет



Цитата(sswt @  28.10.2015,  13:25 Найти цитируемый пост)
feodorv, можете написать как нужно для RemoveFirst, а то я запуталась немножко((( 

Цитата
Думаю, как-то так:
Код

void RemoveAfter(DoublyLinkedList::Node* node)
{
    if( node == nullptr || node->nextNode == nullptr ) return;
    DoublyLinkedList::Node* temp = node->nextNode;
    node->nextNode = temp->nextNode;
    if( node->nextNode != nullptr )
      node->nextNode->prevNode = node;
    else 
      tail = node;
    free(temp);
}


free та как я на Си  пишу....
Но я  же посмотрела как вы  тут сделали и так само написала
Код

void RemoveAfter(DoublyLinkedList* list, DoublyLinkedList::Node* node)
{
if( node == nullptr || node->nextNode == nullptr )]
 return;
    DoublyLinkedList::Node* firstNode = node->nextNode;
    DoublyLinkedList::Node* secondNode = firstNode->nextNode;
secondNode = secondNode->nextNode;
    if (firstNode != nullptr)
    {
        firstNode->prevNode = node;
    }
    else
        list->tail = node;
    free(firstNode);
}


Это сообщение отредактировал(а) sswt - 28.10.2015, 17:38
PM MAIL   Вверх
feodorv
Дата 28.10.2015, 18:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(sswt @  28.10.2015,  17:30 Найти цитируемый пост)
free та как я на Си  пишу....

Вы в этом уверены? Можно посмотреть Ваше определение DoublyLinkedList и DoublyLinkedList::Node?


Цитата(sswt @  28.10.2015,  17:30 Найти цитируемый пост)
Но я  же посмотрела как вы  тут сделали и так само написала

Послушайте. Вы мне напоминаете маленького ребёнка, которого заставили собирать пазл. И вот он попеременно с силой вставляет один неподходящий элемент мозаики в другой и удивляется, почему не получается цельной картины? Всё же программирование лежит в иной плоскости. С одной стороны, это творчество, что Вам пытался донести math64, предлагая несколько вариантов подхода к решению этой незатейливой задачи. С другой стороны - это ясное понимание того, что должно происходить в Вашей программе. Это и логика, это и обработка особых ситуаций, это адекватная реакция программы на любые входные данные. И многое чего ещё. Но это не перебор пазлинок, авось повезёт на этот раз и всё заработает, и заработает правильно. 


У Вас на руках в функции RemoveAfter всего три элемента: node, firstNode, secondNode (и гдет-то на заднем фоне маячит tail). Они взаимосвязаны друг с другом через поля nextNode и prevNode. Абсолютно ничего не мешает Вам взять бумагу и зарисовать эти взаимосвязи. А потом зарисовать то, что должно получиться при выдёргивании из этой цепочки срединного члена - firstNode. 


А потом рассмотреть случай, когда firstNode есть нулевой указатель. Что поменяется в коде в этом случае? Когда нужно проверить firstNode на nullptr, куда в код вставить эту проверку, чтобы не было разименовывания нулевого указателя. Меняется ли в этом случае tail и/или nextNode/prevNode у наших трёх элементов?


А затем рассмотреть случай, когда secondNode есть нулевой указатель (ведь такое может случиться, правда ведь?) Аналогичные вопросы.


Я Вас очень попрошу в устной форме прямо в этой ветке на них ответить. Только тогда Вам станет ясно, что не так в том коде, который Вы привели и который, по Вашему утверждению, Вы сделали после "посмотрела как вы  тут сделали". И почему я должен по десять раз повторять, что:
Цитата(feodorv @  28.10.2015,  17:07 Найти цитируемый пост)
Почему не проверяете secondNode на nullptr? Почему делаете
list->tail = node;
в случае, когда нулевой firstNode


Цитата(sswt @  28.10.2015,  17:30 Найти цитируемый пост)
Думаю, как-то так:

Я Вам написал, и ещё раз напишу:

Вообще, вся логика по проверке на нулевые указатели нарушена полностью (заодно и логика алгоритма). secondNode тоже может быть нулевым указателем, тогда делать secondNode->prevNode никак нельзя. Если уж Вам так не нравится конструкция node->nextNode->prevNode, то реализовывайте её последовательно:
Код

void RemoveAfter(DoublyLinkedList* list, DoublyLinkedList::Node* node)
{
    DoublyLinkedList::Node* firstNode = node->nextNode;

    if( firstNode != nullptr )
    {
        DoublyLinkedList::Node* secondNode = firstNode->nextNode;
    
        if (secondNode != nullptr) //// not firstNode!!!!
            secondNode->prevNode = node;
        else
            list->tail = node;

        free(firstNode);
    }
}


Соглашаться на этот код Вам не обязательно, но с Вас объяснение того, что должно происходить в коде при:
  • firstNode есть nullptr
  • secondNode есть nullptr
  • иначе - ...



--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
math64
Дата 29.10.2015, 08:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 12
Всего: 72



Цитата(sswt @  28.10.2015,  16:45 Найти цитируемый пост)
math64, так ?  та нет лутче поддельности 2 функции  делать

Как можно видеть RemoveFirst и RemoveAfter очень похожи.
В RemoveAfter нужно внести только 2 изменения, чтобы она могла удалять и первый элемент списка:
Код

void RemoveAfter(DoublyLinkedList* list, DoublyLinkedList::Node* node)
{
    // Удаляемый элемент - следующий за node или первый в списке.
    DoublyLinkedList::Node* firstNode = node == nullptr ? list->head : node->nextNode; (1)
    if( firstNode != nullptr )
    {
        DoublyLinkedList::Node* secondNode = firstNode->nextNode;
    
        if (node != nullptr)
            node->nextNode = secondNode;
        else
            list->head = secondNode; // (2)        
        if (secondNode != nullptr) //// not firstNode!!!!
            secondNode->prevNode = node;
        else
            list->tail = node;
        free(firstNode);
    }
}

Или даже так:
Код

void RemoveAfter(DoublyLinkedList* list, DoublyLinkedList::Node* node)
{
    // Ссылка на удаляемый элемент - следующий за node или первый в списке.
    DoublyLinkedList::Node*& firstNodeRef = node == nullptr ? list->head : node->nextNode; (1)
    if( firstNodeRef != nullptr )
    {
        DoublyLinkedList::Node* secondNode = firstNodeRef->nextNode;
        // Note:  firstNodeRef - ссылка,  присваивание node->nextNode или list->head соответственно (2)
        firstNodeRef = secondNode;
        if (secondNode != nullptr) //// not firstNode!!!!
            secondNode->prevNode = node;
        else
            list->tail = node;
        free(firstNode);
    }
}

Но это менее понятно

Добавлено через 6 минут и 12 секунд
Цитата(sswt @  28.10.2015,  17:30 Найти цитируемый пост)
free та как я на Си  пишу....

Код

DoublyLinkedList::Node* firstNode = ...;

Это C++. На C будет
Код

struct Node* firstNode = ...;

Чтобы код работал как на C, так и на C++, нельзя объявлать структуру в структуре и нужно не забывать ключевое слово struct.
PM   Вверх
feodorv
Дата 29.10.2015, 09:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(math64 @  29.10.2015,  08:18 Найти цитируемый пост)
Как можно видеть RemoveFirst и RemoveAfter очень похожи.

Да и вообще, для двусвязного списка делить узлы на "первый" и "следующий" весьма странно (для односвязного - нормально). Достаточно просто функции removeNode, которая удаляет из списка именно тот node, который и передаётся функции removeNode. И уже внутри себя функция removeNode определяет, первый ли это элемент в списке, последний ли или ещё как-то.


Для C придётся ещё избавляться от nullptr.


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
math64
Дата 29.10.2015, 09:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 12
Всего: 72



Цитата(feodorv @  29.10.2015,  09:04 Найти цитируемый пост)
Для C придётся ещё избавляться от nullptr. 

Ну с этим просто:
Код

#ifndef __cplusplus
#define nullptr ((void*)0)


PM   Вверх
sswt
Дата 29.10.2015, 09:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 41
Регистрация: 22.9.2015

Репутация: нет
Всего: нет




math64
 аможете  обяснить вот это: 
Код

DoublyLinkedList::Node* firstNode = node == nullptr ? list->head : node->nextNode;

Как я уже писала я  на Си пишу
Код

#ifndef __DOUBLY_LINKED_LIST_H__
#define __DOUBLY_LINKED_LIST_H__

struct DoublyLinkedList
{
    struct Node
    {
        int value;
        Node* nextNode;
        Node* prevNode;
    };
    Node* head;
    Node* tail;
};
DoublyLinkedList* CreateDoublyLinkedList();
void Release(DoublyLinkedList* list);
void Clear(DoublyLinkedList* list);
void InsertAfter(DoublyLinkedList::Node* node, int value);
void InsertBefore(DoublyLinkedList::Node* node, int value);
void InsertFirst(DoublyLinkedList* list, int value);
void InsertLast(DoublyLinkedList* list, int value);
void PrintForward(const DoublyLinkedList* list);
void PrintBackward(const DoublyLinkedList* list);
void RemoveFirst(DoublyLinkedList* list);
void RemoveAfter(DoublyLinkedList* list, DoublyLinkedList::Node* node);

#endif


PM MAIL   Вверх
math64
Дата 29.10.2015, 10:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 12
Всего: 72



Это - C++.
Надо так:
Код

#ifndef __DOUBLY_LINKED_LIST_H__
#define __DOUBLY_LINKED_LIST_H__
#ifdef __cplusplus
extern "C" {
#else
#ifndef nullptr
#define nullptr ((void*)0)
#endif
#endif
typedef struct Node
{
    int value;
    struct Node* nextNode;
    struct Node* prevNode;
} Node_t;
typedef struct DoublyLinkedList
{
    Node_t* head;
    Node_t* tail;
} DoublyLinkedList_t;
DoublyLinkedList_t* CreateDoublyLinkedList();
void Release(DoublyLinkedList_t* list);
void Clear(DoublyLinkedList_t* list);
void InsertAfter(Node_t* node, int value);
void InsertBefore(Node_t* node, int value);
void InsertFirst(DoublyLinkedList_t* list, int value);
void InsertLast(DoublyLinkedList_t* list, int value);
void PrintForward(const DoublyLinkedList_t* list);
void PrintBackward(const DoublyLinkedList_t* list);
void RemoveFirst(DoublyLinkedList_t* list);
void RemoveAfter(DoublyLinkedList_t* list, Node_t* node);
#ifdef __cplusplus
}
#endif
#endif
 
(с учетом того, чтобы можно было компилироваться как в C, так и в C++)
В C есть оператор ?: поэтому можно писать
Код

Node_t* firstNode = node == nullptr ? list->head : node->nextNode;

Это эквивалентно:
Код

Node_t* firstNode;
if (node == nullptr) firstNode = list->head; else firstNode = node->nextNode;

А вот вместо
Код

Node_t*& firstNodeRef = node == nullptr ? list->head : node->nextNode;

Придётся писать
Код

Node_t** firstNodePtrPtr = node == nullptr ? &list->head : &node->nextNode;


Это сообщение отредактировал(а) math64 - 29.10.2015, 10:30
PM   Вверх
sswt
Дата 29.10.2015, 10:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 41
Регистрация: 22.9.2015

Репутация: нет
Всего: нет



math64, спасибо. Буду  знать

Добавлено @ 10:40
math64,  я написала :
Код

void RemoveAfter(DoublyLinkedList* list, DoublyLinkedList::Node* node)
{
    DoublyLinkedList::Node* firstNode;
    if (node == nullptr)
        firstNode = list->head;
    else
        firstNode = node->nextNode;
    
    if (firstNode != nullptr)
    {
        DoublyLinkedList::Node* secondNode = firstNode->nextNode;
        firstNode = secondNode;
        if (secondNode != nullptr)
            secondNode->prevNode = node;
        else
            list->tail = node;
        free(firstNode);
    }
}
int main()
{
DoublyLinkedList* list = CreateDoublyLinkedList();
    InsertFirst(list, 5);
    InsertFirst(list, 4);
    InsertFirst(list, 6);
    InsertFirst(list, 8);
    PrintForward(list);
    PrintBackward(list);

    //RemoveFirst(list);
    //PrintForward(list);
    //PrintBackward(list);

    RemoveAfter(list, list->head);
    PrintForward(list);
    PrintBackward(list);


    Release(list);
}
return 0;
}

но бага так и есть(  как вы можете увидеть на картинке

Это сообщение отредактировал(а) sswt - 29.10.2015, 10:42

Присоединённый файл ( Кол-во скачиваний: 3 )
Присоединённый файл  1.jpg 15,29 Kb
PM MAIL   Вверх
math64
Дата 29.10.2015, 10:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 12
Всего: 72



Вместо firstNode = secondNode; нужно писать:
Код

        if (node != nullptr)
            node->nextNode = secondNode;
        else
            list->head = secondNode; // (2)

Сокращенная запись возможно только с firstNodeRef или firstNodePtrPtr (если пишете на C):
Код

        /*
         * Разыменовается двойной указатель.
         * Он указывает на &node->nextNode или &list->head соответственно
         */
        *firstNodePtrPtr = secondNode;

PM   Вверх
sswt
Дата 29.10.2015, 12:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 41
Регистрация: 22.9.2015

Репутация: нет
Всего: нет



Я надеюсь я  хоча б эти функци правильно сделала?
Код

DoublyLinkedList::Node* FindFirstValue(DoublyLinkedList* list, int value)
{
    for (DoublyLinkedList::Node* node = list->head; node != nullptr; node = node->nextNode)
    {
        if (node->value == value)
            return node;
    }
    return nullptr;
}
DoublyLinkedList::Node* FindLastValue(DoublyLinkedList* list, int value)
{
    for (DoublyLinkedList::Node* node = list->tail; node != nullptr; node = node->prevNode)
    {
        if (node->value == value)
            return node;
    }
    return nullptr;
}


Выводит нормально.....

Это сообщение отредактировал(а) sswt - 29.10.2015, 12:45
PM MAIL   Вверх
math64
Дата 29.10.2015, 13:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 12
Всего: 72



Правильно. Но в C нельзя объявлять переменую цикла в for:
Код

Node_t* FindFirstValue(DoublyLinkedList_t* list, int value)
{
    Node_t* node;
    for (node = list->head; node != nullptr; node = node->nextNode)
    {
        if (node->value == value)
            return node;
    }
    return nullptr;
}

PM   Вверх
sswt
Дата 30.10.2015, 12:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 41
Регистрация: 22.9.2015

Репутация: нет
Всего: нет




Цитата(feodorv @  29.10.2015,  09:04 Найти цитируемый пост)
Да и вообще, для двусвязного списка делить узлы на "первый" и "следующий" весьма странно (для односвязного - нормально). Достаточно просто функции removeNode, которая удаляет из списка именно тот node, который и передаётся функции removeNode. И уже внутри себя функция removeNode определяет, первый ли это элемент в списке, последний ли или ещё как-то.

 а можете  пример скинуть реализации этой функции? Если есть в интернете
PM MAIL   Вверх
volatile
Дата 30.10.2015, 12:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(sswt @  30.10.2015,  12:09 Найти цитируемый пост)
а можете  пример скинуть реализации этой функции?

Код

void RemoveNode (DoublyLinkedList* list, DoublyLinkedList::Node* node)
{
    (node->prevNode ? node->prevNode->nextNode : list->head) = node->nextNode;
    (node->nextNode ? node->nextNode->prevNode : list->tail) = node->prevNode;
    free (node);
}

PM MAIL   Вверх
feodorv
Дата 30.10.2015, 12:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(sswt @  30.10.2015,  12:09 Найти цитируемый пост)
а можете  пример скинуть реализации этой функции?
Код

// Изымает элемент item из двусвязного списка list
//
// Память, выделенная под item, не высвобождается (так как это не собачье дело данной функции, 
//   item в дальнейшем может использоваться где-нибудь ещё в коде)
//
// Предполагается, что item != NULL и list != NULL, и что item принадлежит list
//
void listRemove( struct list *list, struct item *item)
{
   if( item->prev == NULL )
   { 
      if( (list->head = item->next) == NULL )
         list->tail = NULL;
      else
         list->head->prev = NULL;
   }
   else
   { 
      if( (item->prev->next = item->next) != NULL )
         item->next->prev = item->prev;
      else
         list->tail = item->prev;
   }
}



Цитата(sswt @  30.10.2015,  12:09 Найти цитируемый пост)
Если есть в интернете

Ну, это я оставлю без коментариев)))


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
math64
Дата 30.10.2015, 12:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 12
Всего: 72



Код

// Проверки на то,что node принадлежит list тоже нет.
// Предполагается, что list огранизован правильно (в этом случае код feodorv делает тоже самое)
// Можно разработать отладочный режим (#ifdef DEBUG_DOUBLY_LINKED_LIST),
// в котором в Node_t добавляется поле list,
// а в DoublyLinkedList_t - счетчик элементов count
void RemoveNode(DoublyLinkedList_t* list, Node_t* node)
{
    if (node == nullptr)
        return;
    Node_t* prevNode = node->prevNode;
    Node_t* nextNode = node->nextNode;
    if(nextNode != nullptr)
        nextNode->prevNode = prevNode;
    else
        list->tail = prevNode;
    if(prevNode != nullptr)
        prevNode->nextNode = nextNode;
    else
        list->head = nextNode;
    free(node);
}

void test(void) {
    DoublyLinkedList_t* list = CreateDoublyLinkedList();
    InsertLast(list, 1);
    InsertLast(list, 2);
    InsertLast(list, 3);
    InsertLast(list, 4);
    // D отладочном режиме:
    // В PrintForward() добавить проверку, что list->tail указывет на последний напечатанный элемент
    // и если не совпадает, печатать предупреждение.
    // Также поступать если node->nextNode->prevNode != node и head->prevNode != nullptr
    // и проверять счетчик на соответствие числу элементов в списке и node->list == list
    // если соответсвующие поля были добавлены
    PrintForward(list); // -> 1 2 3 4
    // Провераям удаление nullptr
    RemoveNode(list, nullptr);
    PrintForward(list); // -> 1 2 3 4
    // Проверяем удаление в середине
    RemoveNode(list, list->head->nextNode);
    PrintForward(list); // -> 1 3 4
    RemoveNode(list, list->head);
    // Проверяем удаление первого элемента
    PrintForward(list); // -> 3 4
    // Проверяем удаление последнего элемента
    RemoveNode(list, list->tail);
    PrintForward(list); // -> 3
    // Проверяем удаление с очищением списка
    RemoveNode(list, list->head);
    PrintForward(list); // -> (пустой список)
}


Это сообщение отредактировал(а) math64 - 30.10.2015, 13:15
PM   Вверх
sswt
Дата 30.10.2015, 13:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 41
Регистрация: 22.9.2015

Репутация: нет
Всего: нет



спасибо

Это сообщение отредактировал(а) sswt - 30.10.2015, 13:28
PM MAIL   Вверх
Страницы: (3) [Все] 1 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

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

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1307 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.