试图找出链表问题

时间:2016-07-26 06:33:14

标签: c++ linked-list

#include <iostream>
using namespace std;

struct ListNode
{
    char data;
    ListNode *next;
}*head = NULL, *nodeptr = NULL, *newNode = NULL;

bool isPalindrome(ListNode*);

int main()
{

    char pali[] = "abaaba";//array of chars

    for (int i = 0; pali[i] != '\0'; i++)
    {
        newNode = new ListNode;
        newNode -> data = pali[i]; //places chars into a linked list
        newNode -> next = head;
        head = newNode;// links list together
        nodeptr = head;


        while(nodeptr != NULL)// prints out the chars
        {
            cout << nodeptr -> data;
            nodeptr = nodeptr ->next;
        }

        cout << endl;

        if(isPalindrome(head)) //prints if function true
            cout << "Is a Palindrome" << endl;
        else if(!isPalindrome(head)) //prints if function false
            cout << "Not a Palindrome" << endl;


    }

    return 0;
}
//test if the list is a palindrome
bool isPalindrome(ListNode* headptr)
{
    ListNode* topptr = headptr;//intializes to first char
    ListNode* botptr = headptr;//intializes to first char
    ListNode* temp = NULL;

    if(headptr != NULL && headptr -> next != NULL )//uses to initially test if the list is empty or a singleton
    {

        while(botptr->next != NULL)//places botptr at the last value pointing towards null
        {
            //cout << botptr ->data;
            botptr = botptr -> next ;
        }


        while (topptr != temp ||  topptr -> next != temp ) //reiterates until the list is the same as temp(empty) or if the next topptr(headptr) value is temp(singleton)
        {
            if(topptr -> data != botptr -> data)//stops if two values dont equal. I feel like the main problem is with this comparison.
            {
                return false;
            }

            else if(botptr -> data == topptr -> data)//if two values do equal move topptr and botptr towards the middle by one.
            {

                temp = topptr;
                temp = topptr-> next;
                topptr = temp;//moves topptr down by one
                temp = botptr;
                botptr = topptr; //intializes botptr to the first in the next iteration

                while(botptr -> next != temp)
                {
                    botptr = botptr -> next;// move botptr up by one
                }//places bottom pointer onto the last value pointer towards null or temp
            }

        }
    }
    return true; // returns true if only the list is empty or a singleton
}

我很难找出这个程序的问题。每次我运行它,它都会经历第三次迭代,然后崩溃。出于某种原因,我无法在第二次迭代中获得返回错误比较。当它应该循环为零时,它循环一次,因为topptr等于b,而botptr等于a。

2 个答案:

答案 0 :(得分:0)

这一行看起来非常可疑:

while (topptr != temp ||  topptr -> next != temp ) //reiterates until the list is the same as temp(empty) or if the next topptr(headptr) value is temp(singleton)

temp是一个临时变量,可用于多种用途(特别是topptr的下一个值和botptr后面的项目)。使用这样的变量进行内部范围之外的比较是危险的。

我相信这条线应该是这样的:

while (topptr != botptr && botptr -> next != topptr) //iterates until topptr reaches botptr

此外,我建议您在需要的范围内声明temp变量。换句话说,删除行

ListNode* temp = NULL;

并将else if(botptr -> data == topptr -> data)下方的行更改为

ListNode* temp = topptr;

答案 1 :(得分:0)

由于你做得有点不对劲,我写了更长的批评。如果你遵循它,你也会发现为什么你的程序不能一直工作。首先:

  • 您使用链接列表来表示字符串。为什么不使用std :: string?它可以让你以更简单的方式实现这一切。
  • 您以相反的顺序存储字符串。从技术上来说不是错误的,但是你是第一个在反向单链表中存储字符串的人。
  • 您实现自己的链接列表而不是使用std :: list。
  • 对于真正需要双向迭代的算法,您使用单个链表。
  • 您没有清理任何资源。这不重要,但是当你编写更大的程序时,它是一个好习惯。

完全避开了,让我们来看看来源:

#include <iostream>
using namespace std;

这句话令人不悦:Why is "using namespace std" considered bad practice?

struct ListNode
{
    char data;
    ListNode *next;
}*head = NULL, *nodeptr = NULL, *newNode = NULL;

在这里,您全局声明三个变量,这些变量可以很容易地成为main的一部分。尽量减少每个声明变量的范围。

bool isPalindrome(ListNode*);

int main()
{
    char pali[] = "abaaba";//array of chars

    for (int i = 0; pali[i] != '\0'; i++)

像这样测试pali的结束条件是正确的,但是很麻烦。您可以轻松地测试pali[i]

    {
        newNode = new ListNode;
        newNode -> data = pali[i]; //places chars into a linked list
        newNode -> next = head;
        head = newNode;// links list together
        nodeptr = head;

因此,您的链接列表与输入字符串的顺序相反。鉴于问题没有错,但这是一种非常独特的方式来存储字符串。

此外,您将浏览添加到列表中的每个字符的整个算法(打印和所有内容)。我想这可能是出于调试目的而有意的。

        while(nodeptr != NULL)// prints out the chars
        {
            cout << nodeptr -> data;
            nodeptr = nodeptr ->next;
        }

        cout << endl;

        if(isPalindrome(head)) //prints if function true
            cout << "Is a Palindrome" << endl;
        else if(!isPalindrome(head)) //prints if function false
            cout << "Not a Palindrome" << endl;

第二次测试是多余的;只需完全删除整个if(!isPalindrome(head))测试,只留下else。有些东西要么是回文,要么没有,没有其他可能的结果。运行算法两次'以确保'只是浪费CPU周期。

    }

    return 0;
}
//test if the list is a palindrome
bool isPalindrome(ListNode* headptr)
{
    ListNode* topptr = headptr;//intializes to first char
    ListNode* botptr = headptr;//intializes to first char
    ListNode* temp = NULL;

同样,最小化变量的范围。特别是'temp'可以降到它的使用位置。

    if(headptr != NULL && headptr -> next != NULL )//uses to initially test if the list is empty or a singleton

同样,你使测试比他们需要的更麻烦。只需测试if (headptr && headptr->next),这就足够了。

    {

        while(botptr->next != NULL)//places botptr at the last value pointing towards null
        {
            //cout << botptr ->data;
            botptr = botptr -> next ;
        }


        while (topptr != temp ||  topptr -> next != temp ) //reiterates until the list is the same as temp(empty) or if the next topptr(headptr) value is temp(singleton)

此测试指定不正确; '||'应该是'&amp;&amp;'。

        {
            if(topptr -> data != botptr -> data)//stops if two values dont equal. I feel like the main problem is with this comparison.
            {
                return false;
            }

这种比较很好。

            else if(botptr -> data == topptr -> data)//if two values do equal move topptr and botptr towards the middle by one.
            {

然而,这种比较并非如此。你再次测试一个你已经知道必须是真实的条件。一个简单的'别人'就足够了。额外的if会浪费CPU周期并形成维护危险。

                temp = topptr;
                temp = topptr-> next;
                topptr = temp;//moves topptr down by one

对同一个变量的双重赋值应始终让您感到怀疑。在这种情况下,两个任务都是不必要的;你可以简单地写topptr = topptr->next;

此外,如果topptr和bottomptr之前指向相邻的字符,它们现在将指向相同的字符。这将导致下一个while循环的结束条件永远不会成为真,导致程序崩溃。您需要一个额外的条件:

                if (topptr == botptr)
                    return true;

                temp = botptr;
                botptr = topptr; //intializes botptr to the first in the next iteration

因为你有一个单链表,你不能轻易地将botptr移动到下一个最低位置。您需要再次遍历整个列表以查找新的botptr。因此,算法的运行时成本为O(n ^ 2),这意味着算法的成本是其输入大小的平方。在这种情况下,具有O(n)复杂度的算法是可能的,这是非常优选的。

                while(botptr -> next != temp)
                {
                    botptr = botptr -> next;// move botptr up by one
                }//places bottom pointer onto the last value pointer towards null or temp
            }
        }
    }
    return true; // returns true if only the list is empty or a singleton
}

那么使用std :: string的解决方案是什么样的呢?这有点简单:

bool isPalindrome (const std::string &s) {  
    for (int b=0, e=s.size () - 1; b<e; b++, e--)
        if (s [b] != s [e])
            return false;

    return true;
}

int main () {
    if (isPalindrome ("abaaba"))
        cout << "Is a Palindrome" << endl;
    else 
        cout << "Not a Palindrome" << endl;

    return 0;
}