2016-07-26 29 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 
} 

私はこのプログラムの問題を把握しようとしています。私がそれを実行するたびに、それは3回目の繰り返しを通り、ちょうどクラッシュします。何らかの理由で、私は2番目の反復のために働く戻りfalseの比較を得ることができません。 topptrはbに等しく、botptrはaに等しいので、ゼロをループさせるはずです。リンクリストの問題を理解しようとしています

+0

あなたはクラッシュログとプログラムが失敗した正確な位置を共有できますか?したがって、私たちの問題を確認するのは簡単でしょう – ddb

+0

'temp = topptr;'直後に 'temp = topptr-> next;'は実装しようとしているアルゴリズムや実装方法を完全に理解していないかもしれませんリンクされたリストを使用します。アルゴリズムは基本的なものでなければなりません。リンクされた文字列のリストを作成したら、今使っているのと同じ頭挿入アルゴリズムを使って*別の*を作成しますが、最初のリンクリストをソース入力として列挙します。完了したら、最初から両方の*リストを列挙し始める。それらが各ノードで同一であれば、回文があります(技術的には、比較ループのために半分だけを列挙すればよい)。 – WhozCraig

+0

そして '!isPalindrome(head)'は不必要で、btwです。あなたは既に "not"条件を決めているので、単純な '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; 

行を削除して、あなたは、私が長い批評を書いたかなり間違ってやっているので

ListNode* temp = topptr; 
0

else if(botptr -> data == topptr -> data)以下の行を変更します。あなたがそれに従えば、なぜあなたのプログラムが途中で動作しないのかを知ることができます。はじめに:

  • 文字列を表すためにリンクリストを使用します。なぜ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の終了条件をテストするのは正しいですが、面倒です。 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; 

2番目のテストは冗長です。完全にif(!isPalindrome(head))テスト全体を削除し、elseのままにしてください。何かがパリンドロームかどうか、他の可能な結果はありません。アルゴリズムを2回実行することで、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. 
      { 

しかし、この比較はありません。繰り返しますが、あなたはすでに知っている必要があることがわかっている条件をテストしています。単純な「else」で十分です。追加の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)です。つまり、アルゴリズムのコストは入力サイズの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; 
} 
関連する問題