在C++中删除双向链接类中的节点

rkue9o1l  于 2022-12-15  发布在  其他
关注(0)|答案(2)|浏览(168)

我正在用C++开发一个使用Node类的双向链表类。
我正在尝试创建一个删除函数,如果所需的节点存在,则删除该节点。
但是如果值大于currentPrt,它就退出,不做任何事情,如果小于currentPrt,它就删除节点,程序就会进入打印奇怪值的无限循环。
节点类编码:

// Node.h

class Node {
public:

    explicit Node(int data = 0, Node *nextPtr = nullptr, Node *beforePtr = nullptr);

    int getData() const;

    void setData(int data);

    Node *getNextPtr() const;

    void setNextPtr(Node *nextPtr);

    Node *getBeforePtr() const;

    void setBeforePtr(Node *beforePtr);

    void print() const;

private:
    int data;
    Node *nextPtr;
    Node *beforePtr;

};

x

// Node.cpp

Node::Node(int data, Node *nextPtr, Node *beforePtr) : data(data), nextPtr(nextPtr), beforePtr(beforePtr) {}

int Node::getData() const {
    return data;
}

void Node::setData(int data) {
    Node::data = data;
}

Node *Node::getNextPtr() const {
    return nextPtr;
}

void Node::setNextPtr(Node *nextPtr) {
    Node::nextPtr = nextPtr;
}

Node *Node::getBeforePtr() const {
    return beforePtr;
}

void Node::setBeforePtr(Node *beforePtr) {
    Node::beforePtr = beforePtr;
}

void Node::print() const {

    cout << getData() << endl;

}
// MyList.h

class MyList {

public:
    MyList(Node *currentPrt = nullptr);

    void insert(int value);

    void print() const;

private:
    Node *currentPrt;

};
// MyList.cpp

MyList::MyList(){
    currentPrt = nullptr;
}

void MyList::insert(int value) {

    if(currentPrt == nullptr){
        currentPrt = new Node;
        currentPrt->setData(value);
        currentPrt->setNextPtr(nullptr);
        currentPrt->setBeforePtr(nullptr);

    }
    else{
        if(value > currentPrt->getData()){
            while (currentPrt->getNextPtr() != nullptr && currentPrt->getNextPtr()->getData() < value){
                currentPrt = currentPrt->getNextPtr();
            }

            Node *newPtr = new Node(value);
            newPtr->setNextPtr(currentPrt->getNextPtr());
            if (currentPrt->getNextPtr() != nullptr) // <---
                currentPrt->getNextPtr()->setBeforePtr(newPtr); // <---
            currentPrt->setNextPtr(newPtr);
            newPtr->setBeforePtr(currentPrt);
        }
        else{
            while (currentPrt->getBeforePtr() != nullptr && currentPrt->getBeforePtr()->getData() > value){
                currentPrt = currentPrt->getBeforePtr();
            }
            Node *newPtr = new Node(value);
            if (currentPrt->getBeforePtr() != nullptr){
                currentPrt = currentPrt->getBeforePtr();
                newPtr->setNextPtr(currentPrt->getNextPtr());
                currentPrt->getNextPtr()->setBeforePtr(newPtr); // <---
                currentPrt->setNextPtr(newPtr);
                newPtr->setBeforePtr(currentPrt);
            }
            else{
                currentPrt->setBeforePtr(newPtr);
                newPtr->setNextPtr(currentPrt);
            }
        }
    }



}

void MyList::remove(int value) {

    if (currentPrt != nullptr){
        if(value > currentPrt->getData()){
            while (currentPrt->getNextPtr() != nullptr && currentPrt->getBeforePtr()->getData() > value){
                currentPrt = currentPrt->getNextPtr();
            }
            if (currentPrt->getNextPtr()->getData() == value){
                delete currentPrt->getNextPtr();
            }
        }
        else{
            while (currentPrt->getBeforePtr() != nullptr && currentPrt->getBeforePtr()->getData() > value){
                currentPrt = currentPrt->getBeforePtr();
            }
            if (currentPrt->getBeforePtr()->getData() == value){
                delete currentPrt->getBeforePtr();
            }
        }
    }

}

void MyList::print() const {
    Node *ptr;
    ptr = currentPrt;
    while(ptr->getNextPtr() != nullptr){
        ptr = ptr->getNextPtr();
    }
    for (ptr; ptr != nullptr; ptr = ptr->getBeforePtr()){
        cout << ptr->getData() << endl;
    }

}

的数据
主要:

MyList test;
    test.insert(5);
    test.insert(3);
    test.insert(7);
    test.insert(6);
    test.printAscending();
    std::cout<<endl;
    test.remove(7); // doesn't work but doesn't cause infinit print
    test.remove(5); // doesn't work but doesn't cause infinit print
    test.remove(6); // causes infinit prints
    test.remove(3); // causes infinit prints
    test.printAscending();

仅拆卸(5)、拆卸(7)的输出:

3
5
6
7

3
5
6
7

如果我输入remove(6)(或3),它就会得到无数个数字,如下所示:

2109940880
2109365888
2109348064
2109342032

我的remove实现有什么问题?

yc0p9oo0

yc0p9oo01#

不应该在链表中的节点上执行delete,首先需要将所有引用重新连接到它,也就是说,前面的节点应该将其nextPtr重定向到要删除的节点后面的节点,并且该节点也应该将其beforePtr重定向。
此外,代码在找到匹配值时会删除 next 节点,而不是删除该节点本身。此外,如果该值出现在多个节点中,也没有删除更多节点的规定。
我还建议将该算法一分为二,因为删除 current 节点的部分本身作为一个方法是有用的。
所以我们得到这个:

/* New method for deleting the current node. After deletion the current pointer 
 * will reference the next node if there is one, and otherwise the preceding 
 * one, or if there is none there either, it will be set to null -- the list is
 * empty then.
 */
void MyList::removeCurrent() {
    if (currentPrt == nullptr) return; // Nothing to do
    Node *temp = currentPrt;
    // Rewire the previous and next node so they reference eachother
    if (temp->getBeforePtr() != nullptr) {
        temp->getBeforePtr()->setNextPtr(currentPrt->getNextPtr());
    }
    if (currentPrt->getNextPtr() != nullptr) {
        currentPrt = currentPrt->getNextPtr();
        currentPrt->setBeforePtr(temp->getBeforePtr());
    } else {
        currentPrt = temp->getBeforePtr();
    }
    // Now the temp node is isolated and no more part of the list:
    // It is safe to delete it now.
    delete temp;
}

void MyList::remove(int value) {
    if (currentPrt == nullptr) return; // Nothing to do
    // Go to the right as long as the current node's data is smaller
    while (value > currentPrt->getData() && currentPrt->getNextPtr() != nullptr) {
        currentPrt = currentPrt->getNextPtr();
    }
    // Go to the left as long as the previous node's data is not smaller
    while (currentPrt->getBeforePtr() != nullptr && value <= currentPrt->getBeforePtr()->getData()) {
        currentPrt = currentPrt->getBeforePtr();
    }
    // Arrived at left most node that could have the value we look for.
    // Remove all occurrences
    while (currentPrt != nullptr && value == currentPrt->getData()) {
        removeCurrent();
    }
}
q43xntqr

q43xntqr2#

让我建议一件事:由于您Assert在插入和存储第一个Node时列表是有序的,因此您永远不必按降序搜索-只需按升序搜索。
在你的实现中,你可以修改你所指向的,指向最后一个插入的节点。我看不出这样做有什么好处。只要存储列表的头部,并将其他指针作为局部变量。这会让你的事情变得更容易。
remove中的bug可能是你没有从被删除节点的后继节点和前趋节点中重新分配next和previous指针,调用delete只是释放内存,这也是为什么当试图读取未分配内存时,它会表现得很奇怪。

Node* before = nodeToDelete->getBeforePtr();
Node* next = nodeToDelete->getNextPtr();
before->setNextPtr(next);
next->setBeforePtr(before);
delete nodeToDelete;

相关问题