Может ли кто-нибудь помочь мне с этим связанным списком? C ++ - PullRequest
1 голос
/ 20 февраля 2020

Завтра у меня есть объектно-ориентированный экзамен, и я все еще застрял со связанными списками. По какой-то причине я не совсем понимаю, как они работают или как их правильно реализовать. Я посмотрел много видео и учебных пособий, но это все еще довольно сложно. Я всегда получаю сообщение об ошибке, которое ничего не выводит на консоль, просто пустая черная страница. Может кто-нибудь сказать им, что я делаю не так? Спасибо.

#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();

}

Ответы [ 4 ]

2 голосов
/ 20 февраля 2020

У вас проблема с

  1. PrintAll, где Head не изменяется и делает его бесконечным l oop.
  2. current не инициализирован и имеет доступ к нему в качестве указателя UB

Нижеприведенный фрагмент исправит вашу проблему,

void PrintAll()
{
    node* temp = head;
    while (temp != nullptr)
    {
       std::cout << temp ->name << "\t";
       std::cout << temp ->number;
       temp = temp->next            
    }
}
1 голос
/ 20 февраля 2020

Для начала это объявление в глобальном пространстве имен

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;

Th функция addToList должна принимать первый аргумент с помощью константной ссылки

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

Функция PrintAll имеет бесконечный l oop когда заголовок указателя не является нулевым указателем

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
1 голос
/ 20 февраля 2020

Три вопроса:

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

Вы не изменяете head внутри l oop (зачем вам), поэтому этот l oop будет работать никогда или навсегда.

Второй:

 node* current;
 while (current != NULL)

current в неинициализированном виде. Сравнение с NULL вызывает неопределенное поведение. Всегда инициализируйте свои переменные!

Last:

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

Как и в первом выпуске, условие l oop имеет значение true или false, но оно никогда не меняется, ie l oop либо никогда не работает, либо бесконечный.

Поскольку это упражнение кажется, я оставлю вам исправление кода.

1 голос
/ 20 февраля 2020

Основная проблема с вашим кодом состоит в том, что ваш метод PrintAll написан неправильно, и вы никогда не обновите указатель current. Возможно, вас еще не учили for циклам, но для них это идеальный случай:

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

Первая часть for для l oop инициализирует переменную (которую вы забыли сделать в вашем коде), следующим является конечное условие (как вы найдете в while l oop), а третья часть обновляет переменную каждый цикл через l oop, таким образом пересекая вашу l oop от начала до конца.

Вы можете сделать все это с помощью while l oop, но оно выражает ваши намерения менее четко, поэтому предпочтение следует отдать for l oop. Я также не уверен, почему у вас while l oop проверяется, является ли head нулевым? Так как он не изменяется в течение l oop, нет необходимости повторно проверять его, и - в любом случае - нет никакой выгоды проверять его отдельно, в отличие от простой проверки current после того, как он был инициализирован для head.

В качестве незначительного замечания, если вы используете современную версию C ++, nullptr следует отдавать предпочтение перед NULL.

...