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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Удаления значения в списку. Бага 
:(
    Опции темы
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   Вверх
Страницы: (3) Все 1 [2] 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

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

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

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

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


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

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


 




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


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

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