【问题标题】:Delete Function to Delete a Node in a Doubly Linked List (C++)删除双向链表中节点的删除函数 (C++)
【发布时间】:2020-10-19 02:57:41
【问题描述】:

对于我的数据结构类中的一个项目,我们被指示制作一个创建链接列表的程序。

这里是赋值指令:你的任务是定义和实现一个 List ADT 作为内存中的有序双链表。您的数据将来自名为 ThingsToDo.txt 的输入文本文件。 List 类将连同构造函数和析构函数一起定义列表的核心功能:

  1. 将项目(字符串)插入升序列表中
  2. 从升序列表中删除一个项目(字符串)
  3. 在升序列表中编辑项目(字符串)
  4. 打印有序列表

我已经创建了以下头文件:

using namespace std;

//create a node with data and link fields
struct Node
{
    string info;
    Node * next;
    Node * prev;
};

//the List ADT definition
class List
{
public:

    // construct a List object
    List();

    // Destroy a list object
    ~List();

    // Insert a string into its correct alpha location in the list and return true if the function worked and false otherwise
    bool Insert(string);

    // Delete a string from its location in the list and return true if the function worked and false otherwise (no string found)
    bool Delete(string);

    // Edit a string from its location in the list and return true if the edit worked and false otherwise. 
    bool Edit(string, string);

    // Print all of the nodes info from the beginning to end.
    void Print() const;

private:

    Node * Head;
};

我的问题是我不知道如何在我的 c++ 文件中创建一个好的删除函数。

我已经制作了以下插入和编辑功能,但如果有人可以帮助我创建一个好的删除功能,将不胜感激。

bool List::Edit(string target, string replace)
{
    bool Success = false;
    // first delete the target node calling the Delete function
    if (Delete(target))
    {
        // if deleted, then insert the replace node
        if (Insert(replace))
        {
            Success = true;
        }
    }

    // will only return true if Delete and add both worked , otherwise false
    return Success;
}

/*Function description: insert data into the doubly linked list by placing 
* it into its correct ascending alpha location
*/
bool List::Insert(string data)
{
    bool wasSuccessful = false;

    // Allocate memory for a node and store the address in p.  If new returns
    // false, then memory could not be allocated and the function will exit
    // with failure.

    Node* p = new Node;
    if (p != NULL)
    {
        //store the KEY data in the node
        p->info = data;

        // Logic that handles the insert empty case (CASE 1)
        if (Head == NULL)
        {
            p->next = NULL;
            p->prev = NULL;
            Head = p;
            wasSuccessful = true;
        }
        else
        {
            //Logic if the List is not empty, cur is the traversal pointer, p points
            //to the node to be inserted (CASES 2, 3 AND 4), set traversal
            //pointer cur
            Node* cur = Head;

            //Loop until the node was successfully inserted, the loop
            //looks for the correct insertion point which could be front
            //middle, or last
            while (!wasSuccessful)
            {
                //insert node (p) still greater than current node (cur)
                if (p->info > cur->info)
                {
                    //are we at the last node? condition for last insertion (CASE 2)
                    if (cur->next == NULL)
                    {
                        //insert node at end of list
                        p->next = NULL;
                        p->prev = cur;
                        cur->next = p;
                        wasSuccessful = true;
                    }
                    else
                    {
                        //move the current pointer to the next node
                        cur = cur->next;
                    }
                }
                else
                {
                    //we have found an insertion point, the node to be inserted
                    //is lesser than the current node in the list

                    //Is it an insert front condition? (CASE 3)
                    if (Head == cur)
                    {
                        p->next = Head;
                        p->prev = NULL;
                        Head->prev = p;
                        Head = p;
                    }
                    else
                    {
                        //Logically, this has to be an insert middle case (CASE 4)
                        p->next = cur;
                        p->prev = cur->prev;
                        cur->prev->next = p;
                        cur->prev = p;
                    }
                    wasSuccessful = true;
                }

            }

        }
    }

    return wasSuccessful;
}

我为 Delete 函数编写的唯一内容是:

bool List::Delete(string data)
{
    
}

有没有人可以为我编写删除功能的代码?

【问题讨论】:

  • 第 1 步:创建一个 find 函数,该函数接受要找到的字符串并返回找到的节点(如果未找到,则返回 null)。第 2 步:编写一个删除函数,该函数接受一个指向节点的指针,从列表中删除该节点并deletes。第三步:编写删除函数。使用 find 函数查找要删除的节点,如果找到,请使用 remove 函数将其删除。一般经验法则:当一个问题太大而您的大脑无法吞下时,将其分解为较小的问题。
  • 那我该怎么写呢?对不起,我是一个非常年轻的学生,我一直在与链接列表作斗争。我也处于时间紧缩状态(它的到期时间为 1 小时 45 分钟),而且我对按时完成感到非常压力
  • 这不是您问题的答案,但您可以查看此视频youtu.be/JfmTagWcqoE,了解如何编写无泄漏算法。演讲者是 C++ 社区中非常杰出的人物。我认为你可以学到一些东西来应用到你的项目中。
  • 找到要删除的节点应该很容易。从头开始循环遍历列表中的所有项目,直到找到保存字符串的节点(返回节点)或用完节点(返回nullptr)。删除节点...变得棘手,因为你需要将之前的节点附加到之后的节点,反之亦然,而不会在您仍然需要它时意外地使任何点无效。这就是通过画图检查逻辑真正派上用场的地方。
  • 最后一点:因为所有功能都建立在彼此的基础上,所以在你使用的时候,对每个功能进行详尽的测试。如果您在插入中犯了错误,则无法获得有效的删除,如果您浪费时间为插入中的错误调试删除,那是浪费了您本可以花在其他家庭作业或在酒吧喝啤酒的时间。或者在我的情况下运行冠军赛。想想看,我有时间玩 RPG 的主要原因是我很早就被介绍给调试器。学习使用开发工具附带的任何调试器。为您节省数年的调试时间。

标签: c++ linked-list


【解决方案1】:

假设您已经构建了一个有效的双向链表(其中Head->prevnullptrTail->next [或最后一个节点]),那么删除任何一个节点都是直截了当的。 (我鼓励添加一个Tail 指针,例如Node *Head, *Tail;,其中Tail 总是指向列表中的最后一个节点——尽管进行按顺序插入消除了它提供的O(1) 插入的好处结束)

要有效地添加或删除节点,您必须了解使用指针地址和指针本身迭代列表的概念。这消除了任何特殊情况。

更详细一点,在您的链表中,每个Node 都是一个指向已分配struct Node 的指针,每个指针也有自己的地址。通过同时使用指针的地址和指向节点的指针,您可以用另一个指针(列表中的 next)替换当前指针地址处的内容,然后 delete 最初存储在该地址的分配结构(那里的原始指针)。这使事情变得更加容易,并且在Linus on Understanding Pointers

上进行了更全面的讨论

对于双向链表,您只需更新将存储在当前指针地址的节点的prev 指针,使其指向当前节点的prev 指针的值。

通过同时使用当前指针的地址和指针本身,当您更改存储在当前指针地址的内容时——您仍然有一个指向原来的 struct Node 的指针——您可以和delete一起使用。

总而言之,你可以这样做:

bool List::Delete (std::string data)
{
    Node **ppn = &Head;                     /* pointer to pointer to node */
    Node *pn = Head;                        /* pointer to node */

    /* iterate over each node using the address of poiner and pointer to node */
    for (; pn; ppn = &pn->next, pn = pn->next) {
        if (pn->data == data) {             /* if node data matches data */
            if (pn->next)                   /* if next not nullptr */
                pn->next->prev = pn->prev;  /* update next->prev to current->prev */
            *ppn = pn->next;                /* set node at current address to next */
            delete pn;                      /* delete original node at address */
            return true;                    /* return success */
        }
    }
    
    return false;       /* return failure (node not found) */
}

注意:建议传递引用而不是字符串本身作为参数,例如std::string& data——效率稍高)

未经测试,但应该可以正常工作。仔细查看,尝试一下,如果您有任何问题,请告诉我。

【讨论】:

    猜你喜欢
    • 2011-03-12
    • 2016-10-09
    • 1970-01-01
    • 2013-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-11
    相关资源
    最近更新 更多