首页 > 解决方案 > 从链表中的 getNext()、getPrev() 或 getData() 函数返回 NULL

问题描述

我正在尝试创建一个链接列表,并且目前正在测试一个打印功能,但是为了打印列表中的所有节点,我需要知道长度。

为了找到长度,我需要使用 for 循环从头部循环到当前为 NULL(又名尾部)的时间。

问题是每当列表中的节点设置为 NULL 时,当我使用 getNext() 或任何其他旨在返回 NULL 的函数时,它会导致错误或没有任何反应。

我已经尝试了很长时间来解决这个问题,但我根本找不到我做错了什么。这可能是一个愚蠢的错误,但我找不到它。

创建一个新的空白列表:

LL::LL()
{
    // These are all protected variables
    head = NULL;
    tail = NULL;
    current = NULL;
}

创建一个新的空白节点:

Node::Node()
{
    // These are all protected variables
    data = v_t(); // Value_Type
    prev = NULL;
    next = NULL;
}

使用参数创建一个新节点:

Node::Node(const v_t& d, Node* n, Node* p)
{
    data = d;
    prev = p;
    next = n;
}

长度函数:

int LL::length()
{
    int answer = 0;
    for (current = head; current != NULL; current = current->getNext())
    {
        answer++;
    }
    return answer;
}

将新节点添加到列表的尾部:

void LL::addToTail(const v_t& item)
{
    // ------------(data, next, prev)
    tail = new Node(item, NULL, tail);

    if (tail -> getPrev() != NULL)
    {
        tail -> getPrev() -> setNext(tail);
    }

    if (head == NULL)
    {
        head = tail;
    }
}

下一个返回函数:

Node* Node::getNext() const
{
    return next;
}

其他两个吸气剂的格式相同。

以下是完整的课程:

节点.h

#ifndef CHRIS_NODE
#define CHRIS_NODE

#include "account.h"

class Node
{
    public: // Members that are externally visible

        typedef Account v_t;

        // Default Constructor
        Node();
        Node(const v_t& d, Node* n, Node* p);

        // Destructor
        ~Node();

        // Pointer Getters and Setters
        void setNext(Node* n);
        void setPrev(Node* p);
        Node* getNext() const;
        Node* getPrev() const;

        // Data Getters and Setters
        void setData(v_t& d);
        v_t getData() const;

    private: // Members that are internally visible

        Node* next;
        Node* prev;
        v_t data;

};

#endif

节点.cpp

#include"node.h"

Node::Node()
{
    data = v_t();
    prev = NULL;
    next = NULL;
}

Node::Node(const v_t& d, Node* n, Node* p)
{
    data = d;
    prev = p;
    next = n;
}

Node::~Node(){};

void Node::setNext(Node* n)
{
    next = n;
}

void Node::setPrev(Node* p)
{
    prev = p;
}

Node* Node::getNext() const
{
    return next;
}

Node* Node::getPrev() const
{
    return prev;
}

void Node::setData(v_t& d)
{
    data = d;
}

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

链接列表.h

#ifndef CHRIS_LIST
#define CHRIS_LIST

#include "node.h"

class LL
{
    public: // Members that are externally visible
    typedef Node::v_t v_t;

    LL();
    LL(Node*  h, Node* t, Node* c);
    ~LL();

    int length();

    void addToHead(const v_t& item);

    void addToCurrent(const v_t& item);

    void addToTail(const v_t& item);

    bool search(const v_t& target);

    void removeHead();

    void removeCurrent();

    void removeTail();

    void clear();

    void printList();

    protected: // Members that are internally visible
    Node* head;
    Node* tail;
    Node* current;
};


#endif

链接列表.cpp

#include "linklist.h"
#include <iostream>

using namespace std;

LL::LL()
{
    head = NULL;
    tail = NULL;
    current = NULL;
}

LL::LL(Node*  h, Node* t, Node* c)
{
    head = h;
    tail = t;
    current = c;
}

LL::~LL()
{
    clear();
        
}

int LL::length()
{
    int answer = 0;
    for (current = head; current != NULL; current = current->getNext())
    {
        answer++;
    }
    return answer;
}

void LL::addToHead(const v_t& item)
{
    head = new Node(item, head, NULL);

    if (head -> getNext() != NULL)
    {
        head -> getNext() -> setPrev(head);
    }

    if (tail == NULL)
    {
        tail = head;
    }
}

void LL::addToCurrent(const v_t& item)
{
    Node* newNode = new Node(item, current, current->getPrev());
    current->setPrev(newNode);
    newNode->getPrev()->setNext(newNode);
    current = head;
}

void LL::addToTail(const v_t& item)
{
    tail = new Node(item, NULL, tail);

    if (tail -> getPrev() != NULL)
    {
        tail -> getPrev() -> setNext(tail);
    }

    if (head == NULL)
    {
        head = tail;
    }
}

bool LL::search(const v_t& target)
{
    for (current = head; current != NULL; current = current -> getNext())
    {
        if (target == (current -> getData()))
        {
            cout << "The data is stored in " << current << "." << endl;
            return true;
        }
    }
    return false;
}

void LL::removeHead()
{
    Node* temp = head;
    head = head -> getNext();
    if (head != NULL)
    {
        head -> setPrev(NULL);
    }
    else
    {
        tail = NULL;
    }
    delete temp;
}

void LL::removeCurrent()
{
    if (current == head) 
    {
        removeHead();
    }
    else if (current == tail)
    {
        removeTail();
    }

    current -> getNext() -> setPrev(current -> getPrev());
    current -> getPrev() -> setNext(current -> getNext());

    delete current;
    current = head;
}

void LL::removeTail()
{
    Node* temp = tail;
    tail = tail -> getPrev();
    if (tail != NULL)
    {
        tail -> setNext(NULL);
    }
    else
    {
        head = NULL;
    }
    delete temp;
}

void LL::clear()
{
    while (head != NULL)
    {
        removeHead();
    }
}

void LL::printList()
{
    if (LL::length() == 0)
    {
        cout << "List Empty.\n";
    }
    else
    {
        current = head;

        for (int i = 1; i <= LL::length(); i++)
        {
            if (current != NULL)
            {
                cout << "Node " << i << ": " << current -> getData() << endl;
                current = current -> getNext();
            }
        }
    }
}

帐户.h

#ifndef CHRIS_ACCOUNT
#define CHRIS_ACCOUNT

#include <string>
#include <iostream>
using namespace std;

class Account
{
public:
    // Members that are externally visible

    // These are member functions

    // Constructor
    // Precondition:    none
    // Postcondition:   A new instance of account is created and its 
    //                  instance data initialsed to either zero or a 
    //                  parameter-provided value
    Account(const string nm = "", const double initialValue = 0.0);

    // Members that mutate data

    // Precondition:    acct_balance has been initialised
    // Postcondition:   amount is added to the acct_balance
    void deposit(const double amount);

    // Precondition:    acct_balance has been initialised
    // Postcondition:   amount is subtracted from the acct_balance
    void withdraw(const double amount);

    void setName(const string nm);

    // Members that query data

    // Precondition:    acct_balance has been initialised
    // Postcondition:   The value of acct_balance is returned
    double balance() const;

    // Precondition:    acct_balance has been initialised
    // Postcondition:   Returns true if acct_balance is greater 
    //                  than zero, false otherwise
    bool has_funds() const;

    string getName() const;


private:

    double acc_balance;
    string name;
};

bool operator == (Account acc1, Account acc2);

ostream& operator << (ostream& out, const Account acc);

// close the macroguard
#endif 

帐号.cpp

#include "Account.h"

Account::Account(string nm, double initialValue)
{
    acc_balance = initialValue;
    name = nm;
}

void Account::deposit(double amount)
{
    acc_balance += amount;
}

void Account::withdraw(double amount)
{
    acc_balance -= amount;
}

double Account::balance() const
{
    return acc_balance;
}

bool Account::has_funds() const
{
    if (acc_balance > 0.0) 
    {
        return true;
    } 
    else 
    {
        return false;
    }
}

string Account::getName() const
{
    return name;
}

void Account::setName(string nm) 
{
    name = nm;
}

bool operator == (Account acc1, Account acc2)
{
    if (acc1.getName() == acc2.getName() && acc1.balance() == acc2.balance())
    {
        return true;
    }
    else
    {
        return false;
    }
}

ostream& operator << (ostream& out, const Account acc)
{
    out << "(" << acc.getName() << ", " << acc.balance() << ")\n";
    return out;
}

银行.cpp

#include <iostream>
#include <cstdlib>
#include <string>
#include "Account.h"
#include "node.h"
#include "linklist.h"

using namespace std;

int main()
{

   int amount = 0;

   cout << "How many accounts?\n";
   cin >> amount;

   LL* LL1 = new LL();

   for (int i = 1; i <= amount; i++)
   {
       string nm;
       double iv;

       cout << "What is the name for account " << i << "?\n";
       cin >> nm;
       cout << "What is the initial value for account " << i << "?\n";
       cin >> iv;

       Account newAcc(nm, iv);
       LL1 -> addToTail(newAcc);
   }

    LL1 -> printList();

    return EXIT_SUCCESS;
}

如果您需要更多信息或代码,请告诉我:)

标签: c++linked-listnullnodes

解决方案


当我使用getNext()或任何其他旨在返回 NULL 的函数时,什么都没有发生。

那是因为您没有在方法中使用结果。您的循环永远不会为. 改变这个:getNext()lengthcurrent

for (current = head; current != NULL; current->getNext())

至:

for (current = head; current != NULL; current = current->getNext())

定义currentLL类的实例成员是一种反模式。这样的引用应该是一个局部变量,在需要它的函数中定义。它不应该是您的链表状态的一部分。

因此,无论您在哪里使用current,都将其定义为局部变量:

Node * current = head;

为了打印列表中的所有节点,我需要知道长度。

不必要。您可以在没有以下情况下更改您的printList功能length

void LL::printList()
{
    Node * current = head;
    if (current == NULL)
    {
        cout << "List Empty.\n";
    }
    else
    {
        for (int i = 1; current != NULL; i++, current = current -> getNext())
        {
            cout << "Node " << i << ": " << current -> getData() << endl;
        }
    }
}

如果您保留调用的版本length并继续使用实例变量current,则循环将不会循环,因为调用length()将改变current(在您初始化之后),并将其设置为NULL.

如果你真的想要实例变量current,那么只在真正需要设置的地方改变它,比如在search. 但它不应该被length()or改变printList(),这不应该改变你的实例的状态。因此,length()printList()应该使用局部变量,而不是实例变量。


推荐阅读