2016-07-26 2 views
0
#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 
} 

Мне трудно найти способы решить эту проблему. Каждый раз, когда я запускаю его, он проходит третью итерацию и просто падает. По какой-то причине я не могу получить ложное сравнение return для второй итерации. Он пеет один раз, когда он должен зацикливать нуль, так как topptr равно b, а botptr равно a.Попытка разобраться в связанных проблемах с перечнем

+0

Вы можете поделиться журналом сбоев и точным положением, в котором программа не работает? так что было бы легко проверить проблему для нас – ddb

+0

'temp = topptr;' сразу же следует 'temp = topptr-> next;' предлагает вам не полностью понять алгоритм, который вы пытаетесь реализовать, или как его реализовать используя связанные списки.Алгоритм должен быть базовым. Создав связанный список символов, создайте * другой *, используя тот же алгоритм головок, который вы используете сейчас, но перечисляя первый связанный список в качестве исходного ввода. После этого запустите перечисление * обоих * списков с самого начала. Если они одинаковы на каждом узле, у вас есть палиндром (и технически вам нужно только перечислить * половину * для цикла сравнения). – WhozCraig

+0

И '! IsPalindrome (head)' бесполезно, кстати. Простой 'else' достаточно, так как вы уже определили условие« нет ». – WhozCraig

ответ

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; 
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; 

Здесь вы глобально объявить три переменные, которые могли бы просто как легко быть частью основного. Попытайтесь свести к минимуму объем каждой объявленной переменной.

bool isPalindrome(ListNode*); 

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

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

Тестирование конечного состояния для пали, как будто это правильно, но громоздко. Вы можете так же легко проверить 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) 

Этот тест указан неверно; '||' должен быть «& &».

 { 
      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 

Двойное присвоение одной и той же переменной должно всегда выглядеть подозрительно для вас. В этом случае оба назначения не нужны; вы можете просто написать 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; 
} 
Смежные вопросы