【问题标题】:Can someone help me with this linked list? C++有人可以帮我处理这个链接列表吗? C++
【发布时间】:2020-06-04 18:29:27
【问题描述】:

我明天有一个面向对象的考试,但我仍然坚持使用链表。出于某种原因,我不太了解它们是如何工作的或如何正确实施它们。我看过很多视频和教程,但它仍然很复杂。我总是收到一个错误,它不会在控制台上打印任何内容,只是一个空白的黑页。有人可以告诉他们我做错了什么吗? 谢谢。

#include <iostream>
#include <string>

using namespace std;

struct node
{
    string name;
    int number;
    node* next;
};
struct node* head = 0;

class Employees
{
private:
    node* head, * tail;
public:
    Employees()
    {
        head = NULL;
        tail = NULL;
    }
    void addToList(string Name, int Num)
    {
        node* n = new node;
        n->name = Name;
        n->number = Num;
        n->next = NULL;
        if (head == NULL)
        {
            head = n;
            tail = n;
        }
        else
        {
            tail->next = n;
            tail = tail->next;
        }
    }
    void PrintAll()
    {
        while (head != NULL)
        {
            node* current;
            while (current != NULL)
            {
                cout << current->name << "\t";
                cout << current->number;
            }
        }
    }
};

int main()
{
    Employees a;
    a.addToList("Robert", 54);
    a.addToList("Manny", 77);

    a.PrintAll();

}

【问题讨论】:

  • 有人能告诉他们我做错了什么吗? 没有使用你的调试器来弄清楚你的代码是如何无法按预期工作的。
  • 您的PrintAll() 有错误。你有node* current; 然后while (current != NULL) 节点当前在哪里得到一个值?
  • while (current != NULL) 当你达到这个条件时,current 的值是多少?同样在循环内你不要修改current,即一旦进入你就永远不会离开循环。
  • 顺便说一句,“一旦进入你就永远不会离开循环”严格来说是错误的。您的代码具有未定义的行为,这就是所有可以肯定的说法

标签: c++ class linked-list singly-linked-list definition


【解决方案1】:

对于初学者来说,这个声明在全局命名空间中

struct node
{
    string name;
    int number;
    node* next;
};
struct node* head = 0;
^^^^^^^^^^^^^^^^^^^^^

是多余的,无处使用。删除它。

最好让结构节点成为Employees类的内部成员。例如

class Employees
{
private:
    struct node
    {
        string name;
        int number;
        node* next;
    } *head = nullptr, *tail = nullptr;
    //...   

构造函数没有什么特别的。所以可以定义为默认构造函数。

 Employees() = default;

函数addToList 应该通过常量引用接受第一个参数

void addToList( const string &Name, int Num )
                ^^^^^^^^^^^^^^^^^^

函数PrintAll在指针头不是空指针时无限循环

void PrintAll()
{
    while (head != NULL)
    {
        //...
    }
}

而且它调用未定义的行为,因为使用的指针当前没有初始化

node* current;
while (current != NULL)

该函数应使用限定符 const 声明,因为它不会更改列表本身。

您还需要一个析构函数来释放节点动态分配的内存。您也可以禁止复制构造和分配。

这是一个演示程序,展示了如何实现该类。

#include <iostream>
#include <string>

using namespace std;

class Employees
{
private:
    struct node
    {
        string name;
        int number;
        node* next;
    } *head = nullptr, *tail = nullptr;

public:
    Employees() = default;

    ~Employees()
    {
        while ( head != nullptr )
        {
            node *tmp = head;
            head = head->next;
            delete tmp;
        }
        tail = nullptr;
    }

    Employees( const Employees & ) = delete;
    Employees & operator =( const Employees & ) = delete;

    void addToList( const string &Name, int Num )
    {
        node *n = new node { Name, Num, nullptr };

        if ( head == nullptr )
        {
            head = n;
            tail = n;
        }
        else
        {
            tail->next = n;
            tail = tail->next;
        }
    }

    void PrintAll() const
    {
        for ( node *current = head; current != nullptr; current = current->next )
        {
            cout << current->name << ' ';
            cout << current->number << '\t';
        }
    }
};

int main()
{
    Employees a;
    a.addToList( "Robert", 54 );
    a.addToList( "Manny", 77 );

    a.PrintAll();

    cout << endl;
}

程序输出是

Robert 54   Manny 77

【讨论】:

    【解决方案2】:

    三个问题:

    while (head != NULL)
    {
        /*...*/
    }
    

    您不会在循环内修改head(为什么会这样),因此该循环将永远运行或永远运行。

    第二:

     node* current;
     while (current != NULL)
    

    current 未初始化。将其与 NULL 进行比较会调用未定义的行为。始终初始化您的变量!

    最后:

    while (current != NULL)
    {
        cout << current->name << "\t";
        cout << current->number;
    }
    

    与第一个问题类似,循环条件是truefalse,但它永远不会改变,即循环要么永远运行,要么无限运行。

    由于这似乎是一个练习,我将把它留给你来修复代码。

    【讨论】:

      【解决方案3】:

      您的代码的主要问题是您的PrintAll 方法编写不正确,并且您从未更新您的current 指针。也许你还没有学过 for 循环,但这对他们来说是一个理想的例子:

      for(node* current = head; current != NULL; current = current->next) {
        cout << current->name << "\t" << current->number;
      }
      

      for 循环的第一部分初始化变量(您在代码中忽略了这样做),接下来是结束条件(正如您在 while 循环中找到的那样),第三部分更新变量通过循环的每个循环,从而从头到尾遍历你的循环。

      您可以使用while 循环来完成所有这些操作,但它不太清楚地表达您的意图,因此应该首选for 循环。我也不确定为什么你有一个while 循环检查head 是否为空?由于它在循环期间不会更改,因此无需重复检查它,并且 - 在任何情况下 - 单独检查它与在初始化为 head 后简单地检查 current 相比没有优势。

      作为一个小提示,如果您使用的是现代 C++ 版本,nullptr 应该优先于 NULL

      【讨论】:

        【解决方案4】:

        你有问题

        1. PrintAll 其中Head 保持不变并使其无限循环。
        2. current 未初始化,作为指针访问它是 UB

        下面的 sn-p 应该解决你的问题,

        void PrintAll()
        {
            node* temp = head;
            while (temp != nullptr)
            {
               std::cout << temp ->name << "\t";
               std::cout << temp ->number;
               temp = temp->next            
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2016-04-28
          • 1970-01-01
          • 1970-01-01
          • 2015-10-03
          • 1970-01-01
          • 2021-04-07
          • 2020-08-26
          • 2015-12-06
          • 1970-01-01
          相关资源
          最近更新 更多