我正在尝试创建一个链表,目前正在测试打印函数,但为了打印列表中的所有节点,我需要知道长度。
为了找到长度,我需要使用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;
}
其他两个getter的格式相同。
下面是完整的类:
node.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
node.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;
}
linklist.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
linklist.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();
}
}
}
}
account.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
account.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;
}
bank.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;
}
如果您需要更多的信息或代码,请告诉我:)
当我使用
getNext()
或任何其他意味着返回NULL的函数时,什么都不会发生。
那是因为你们在length
方法中没有使用getNext()
的结果。你的循环从来没有给current
分配一个新的引用。改变这个:
for (current = head; current != NULL; current->getNext())
:
for (current = head; current != NULL; current = current->getNext())
将current
定义为LL
类的实例成员是一个反模式。这样的引用应该是一个局部变量,在需要它的函数中定义。它不应该是链表状态的一部分。
所以当你使用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
,那么只在真正需要set的地方更改它,就像search
一样。但是它不应该被length()
或printList()
改变,它们不应该改变实例的状态。因此,在length()
和printList()
中,您应该使用本地变量,而不是实例变量。