遍历链表时的无限循环



删除和查看整个队列会导致问题——我假设这是一个无限循环的遍历情况。它可以很好地添加元素,但在用户选择2个或3个元素后立即停止执行。

我只是在代码之前添加了几行随机文本,因为堆栈不允许这么大的代码带有小的解释。

事实上,这是一个错误,因为它是一个充满活力的平台,一个充满激情的平台,另一个平台是一个真正的发明者和准建筑师。Nemo enim ipsam voluptems qui voluptam sat aspnature aut odit aut fugit,sed qui a consequuntur magni dolores eos qui rational voluptim sequi nesciunt。Neque porro quisquam est,qui dolorem ipsum quia dolor sit amet,consectetur,adipisci velit,sed quia non-numquam eius modi tempora incident ut labore and dolore magnam aliquam quaerat volutitem。这是一个非常小的夜晚,是一个充满活力的公司,还是一个充满激情的商品?你的代表是谁?

#include<iostream>
using namespace std;
class linkedlist
{
struct node
{
int number;
node *next;
}*HEAD;
public:
void addelement(int num);
void exitelement();
void displayqueue();
};
void linkedlist::addelement(int num)
{
node *t;
t= new node;
t -> number=num;
t -> next=HEAD;
HEAD=t;
cout<<num<<"has successfully been added to the queue /n";
}
void linkedlist::exitelement()
{
node *t;
t=HEAD;
while(t -> next !=NULL)
{
t=t -> next;
}
cout<<t->number;
delete t;
}
void linkedlist::displayqueue()
{
node *t;
t=HEAD;
while(t->next !=NULL)
{
cout<<t -> number<<"t";
t=t->next;
}
cout<<" n that's the end of the list n";
}
int main()
{
int lol;
linkedlist m;
int rpt=1;
while(rpt==1)
{
int c;
cout<<"n please select 1 to add an element, 2 to remove an element from the queue and 3 to display the entire queue n";
cin>>c;
cout<<"/n";
if(c==1)
{
cout<<"enter the number: ";
cin>>lol;
m.addelement(lol);
}
else if(c==2)
{
m.exitelement();
}
else if(c==3)
{
m.displayqueue();
}
else
{
cout<<"you have entered an invalid input. Sorry n";
}
cout<<"n Do you wish to start the queue again??? n";
cin>>rpt;
}
}

尝试在linkedlist::exitelement()linkedlist::displayqueue()中迭代列表的方式存在许多问题。但在我们查看细节之前,当您使用箭头运算符(->)时,两侧都没有空格。这意味着您将执行t->next = HEAD;而不是t -> next = HEAD;('='两侧的空格是可选的,但为了可读性,鼓励使用)。您还需要确保在类中声明的HEAD指针通过直接初始化或提供构造函数初始化为nullptr。目前,这将做到:

class linkedlist
{
struct node {
int number;
node *next;
} *HEAD = nullptr;
...

您的linkedlist::addelement(int num)函数很好,它使用一个名为正向链接的方法在每次添加时将节点添加到列表的开头。唯一需要注意的是,您的列表最终以与输入相反的顺序结束(在某些情况下需要,但在其他情况下不需要)

您的linkedlist::exitelement()不起作用,因为它没有提供在删除当前节点之前将prev->next指针设置为nullptr的方法。处理这一问题的简单方法是,在迭代到列表末尾时,使用当前节点和最后节点的地址以及指向当前节点的指针。请参阅了解指针上的Linus。以这种方式处理列表迭代时,您不必检查任何特殊条件。

(这里只需要检查if (HEAD == nullptr)来打印"(queue-empty)"消息,以防您试图从空列表中删除节点,并防止在这种情况下为要删除的节点上的编号的cout取消引用nullptr)。

使用指针地址的好处是不会在内存中发生变化。(您可以更改或删除存储在那里的内容,但地址本身不会更改)通过使用node **指针(而不是指针本身node*)跟踪地址,您只需使用指针迭代到列表的末尾(末尾将是nullptr),然后是delete存储在最终地址的内容,然后将该位置的内存设置为nullptr。(当您删除最后一个节点时,您必须将列表中删除节点之前的节点的->next指针设置为nullptr,否则您将不知道列表的末尾在delete之后的位置)例如:

void linkedlist::exitelement()
{
if (HEAD == nullptr) {
cout << "(queue-empty)n";
return;
}
node **ppt = &HEAD,     /* address of HEAD */
**last = ppt;       /* address of last (initialized to HEAD) */
node *pt = HEAD;        /* pointer to node */
while (pt != nullptr) { /* loop over each node */
last = ppt;         /* set last to address of previous */
ppt = &pt->next;    /* set address of current to next */
pt = pt->next;      /* set current to next */
}
cout << (*last)->number << 'n';
delete *last;           /* delete node at address of last */
*last = NULL;           /* set memory at last address to nullptr */
}

(注意:列表上的迭代出现while (pt != nullptr)而不是while (pt->next != nullptr)——下面的linkedlist::displayqueue()也是如此)

当迭代一个列表来打印每个节点的值时,不需要跟踪指针的地址。您只需使用一个简单的指针,检查节点是否为nullptr,如果不是,则打印该节点的number,推进指针并重复,例如

void linkedlist::displayqueue()
{
if (!HEAD) {
cout << "queue-emptyn";
return;
}
node *t = HEAD;
while (t != nullptr) {
cout << t->number << "t";
t = t->next;
}
cout << "n(end of the list)n";
}

剩下的问题是未能验证每个输入,以及在输入失败时未能清空stdin。至少,你必须同时做到这两点。您的程序输出使您几乎不可能遵循代码的要求。你的菜单都在一行,很难阅读。换行符'n'NOT'/n'表示(它只是一个正斜杠和一个字面'n'字符)。

清理您的菜单和换行问题,您的菜单现在显示为:

please select:
1 to add an element
2 to remove an element
3 to display the entire queue
choice:

而不是在一条混乱的线上。总的来说,你可以做一些类似于以下的事情:

int main (void)
{
int lol;
linkedlist m {};
int rpt = 1;
m.addelement(10);    /* queue elements 10, 20, 30 added for testing to avoid */
m.addelement(20);    /* having to navigate the menu and input multiple times */
m.addelement(30);    /* (remove when you are done testing) */
while (rpt == 1)
{
int c;
cout << "nplease select:nn"
"  1 to add an elementn"
"  2 to remove an elementn"
"  3 to display the entire queuenn"
"choice: ";
if (!(cin >> c)) {  /* validate EVERY input */
cerr << "error: invalid integer - choice.n";
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), 'n');
continue;
}
if (c == 1) {
cout << "enter the number: ";
if (cin >> lol)
m.addelement(lol);
else {
cerr << "error: invalid integer input.n";
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), 'n');
}
}
else if (c == 2) {
m.exitelement();
}
else if (c == 3) {
m.displayqueue();
}
else {
cout << "you have entered an invalid input. Sorry n";
}
cout << "nDo you wish to start the queue again? (0-no, 1-yes): ";
if (!(cin >> rpt)) {
cerr << "error: invalid integer input.n";
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), 'n');
}
}
}

单独测试菜单和列表

也就是说,菜单的繁琐特性使得测试列表操作变得困难,因为必须重复输入菜单选项并继续输入以添加和删除节点。相反,想想如何让测试算法变得更容易(与用户界面分离)。例如,在这里,您可以添加一个简单的is_empty()成员函数,以便在列表为空时进行报告。这将允许您重复调用m.exitelement();,直到它为空,而无需输入任何内容。

您可以简单地添加is_empty()成员函数:

...
public:
void addelement(int num);
void exitelement();
void displayqueue();
bool is_empty() { return HEAD == nullptr; }
...

现在要测试你的列表,完全删除你的菜单,你可以将你的列表测试代码减少到以下内容:

int main (void)
{
linkedlist m {};
for (int i = 1; i < 40; i++)
m.addelement(i);
m.displayqueue();
do
m.exitelement();
while (!m.is_empty());
m.exitelement();        /* just to validate it works as intended */
}

(使测试您的列表更加容易:)

仔细看看,如果你还有问题,请告诉我。

在addelement()方法中,无论何时添加新节点,都会放入

t -> next=HEAD;

因此,对于所有节点,下一个永远不会为空。因此,display和exiteElement函数将始终处于无穷大循环中。

除此之外,您的整个linkedlist实现还有一些其他问题,如果您希望任何功能都能正常工作,则需要解决这些问题。您可以查看此链接以更好地理解。

相关内容

  • 没有找到相关文章

最新更新