Изтриване на възел в кръгъл свързан списък

Имам основен проблем със свързания списък, който се опитах да разреша по-долу. Ще се радвам на всякакви приноси относно моя подход, коректността на алгоритъма (и дори стила на кодиране). Проблемът изисква функция, която изтрива всички срещания на int в кръгъл свързан списък и връща всеки възел от списъка или NULL (когато списъкът е null).

Ето малко C++ код, който имам досега:

struct Node{
    Node* next;
    int data;
};

Node* deleteNode(Node* &node, int num){

    if(!node){
        return NULL;
    }

    Node* given = node;
    Node* del;

    while(node->next != given){
        if(node->next->data == num){
            del = node->next;
            node->next = node->next->next;
            delete del;
        }
        node = node->next;
    }

    //Check if the first node needs to be deleted, with variable node pointing to last element
    if(given->data == num){
        node->next = given->next;
        delete given;
    }

    return node;
}

person KT100    schedule 24.04.2013    source източник
comment
Поискахте стилови коментари, така че ето един. Трябва да създадете клас List и deleteNode трябва да бъде частен член на този клас. Трябва да мислите от гледна точка на интерфейса, който вашият код представя на потребителя на вашия код. Никой потребител на клас List не се нуждае или не иска да знае за Nodes, те просто искат да добавят и премахват елементи от своя списък. Разгледайте std::list за пример за добър дизайн.   -  person john    schedule 24.04.2013


Отговори (2)


delete node; трябва да бъде delete del;.

Освен това използвайте Node* node като параметър вместо Node* &node, което ще предотврати преминаването на не-l-стойности.

p.s. Забравихте точка и запетая след дефиницията на структура? :)

person yzn-pku    schedule 24.04.2013
comment
Трябва ли да поставите ; след структура? Мислех, че това е само за класове - person Jesse Moreland; 24.04.2013
comment
@yzn-pku Благодаря! Първият проблем е правописна грешка :) Относно 2-ра точка, поправете ме, ако греша, но мисля, че ако използвам Node* node, тогава няма да променя действителния указател на възел. Ето защо използвах препратка към указателя на възел. И да, ще добавя точка и запетая след структурата :) - person KT100; 24.04.2013
comment
@Jesse, в C++ структура и клас са почти едно и също нещо, единствената разлика е модификаторът за достъп по подразбиране: той е public за структури и private за класове - person SingerOfTheFall; 24.04.2013
comment
@KT100 Трябва ли също да върнете възела чрез параметъра? Ако не, нямате нужда от &. - person RedX; 24.04.2013

Без да следвам цялата ви логика, виждам с един поглед, че този код не може да работи.

Проверявате дали списъкът за въвеждане е празен и това е единственият случай, в който вашият код връща NULL. Но какво се случва, ако ви бъде подаден списък, в който всички елементи трябва да бъдат изтрити?

Този проблем също има тънкост. За да проверите дали сте попълнили кръгъл списък, трябва да сравните с първия адрес, за да видите дали сте се свързали обратно към началото. Ако обаче този елемент е бил изтрит, тогава според стандарта C++ вие дори нямате право да използвате адреса му в сравнение.

За да избегнете извършването на две преминавания през елементите, които трябва да бъдат изтрити, един възможен трик е да "прекъснете цикъла" при стартиране на итерация, така че да можете да проверите за NULL вместо да проверявате за адреса на началния възел.

person 6502    schedule 24.04.2013
comment
Ъгловият случай, когато всички елементи трябва да бъдат изтрити, е страхотен улов. Тогава този код определено ще се провали. Как бихте препоръчали промяна на цикъла while, за да се погрижите за това? Мисля в посока на това да гарантирам, че указателите, които се изтриват, са зададени на NULL, така че да гарантираме, че в крайна сметка променливият възел, който се връща, е равен на NULL за този случай. Моля, обърнете внимание, че проверявам за първия елемент от списъка само накрая, така че вашият 2-ри коментар няма да е валиден AFAIK. Също така, бихте ли разяснили допълнително (с примерен код) за прекъсване на цикъла? Благодаря! - person KT100; 24.04.2013
comment
Сега отделих време да прочета кода ви и виждам друг проблем в подхода ви. Ако в крайна сметка установите, че възелът given трябва да бъде изтрит, вие също трябва да поправите указателя, който се свързва към него. Например като се има предвид списъкът (2, 3, 4, 2, 5, 7), ако ви бъде дадено първото 2 и ви бъде казано да изтриете всички 2, ще завършите с (2, 3, 4, 5, 7) след цикъла и след това проверявате за изтриване на given, но също така трябва да поправите указателя next на възел 7. - person 6502; 24.04.2013