C ++中的回文

时间:2017-10-04 05:28:10

标签: c++

我正在尝试制作一个程序,使用堆栈(w pop,push等)读取一个文本文件,其中包含大量一次一个句子,并输出每行是否为回文序列(拼写相同向前和向后拼写的单词)。我认为它非常接近完成程序,但即使字符串是回文,它也只返回false。我希望它在字符串实际上是回文时返回true。

编辑:尝试用三个堆栈代替一个新方法。每次都从bool tf那里得到错误的回报。

 int main() {
Stack s(100);   // Initialize two different stacks
Stack q(100);
Stack temp(100);
string line;        // String to hold each individual line of the file
char letter;
 char x;            // For comparisons
 char y;

// open the file
ifstream input;

input.open(READFILE);

// Check that it is open/readable
if (input.fail()) {
    cout << endl << "Sorry, file not available, exiting program. Press enter";
    cout << endl;

    cin.get();  // Grab the enter
    return 0;
}

while (getline(input, line)) {                      // Read the file line-by-line into "line"
    cout << "The line: " << line << endl;

    int length = line.length();                     // Sets length equal to string length

    for (int i =0; i<length; i++){                  // Capitalizes string
            line[i] = toupper(line[i]);
    }

    for (int i = 0; i < length; i++) {              // Loop through for every letter in the line
        if (line[i] == ' ' ) {
            line.erase(i,1);        // Takes spaces out of the line
            length--;
        }
        if (ispunct(line[i])){  
        length--;
        }
        if (!ispunct(line[i])){                     // Removes punctuation
        letter = line[i];                           // Push each letter onto the stack
        s.push(letter);         
        }
    }

    for (int i = 0; i < length; i++) {          // Popping half the letters off of the s stack 
        s.pop(letter);                              // and pushing them onto the q stack
        q.push(letter);
        temp.push(letter);
    }

    for (int i = 0; i < length; i++) {
        temp.pop(letter);
        s.push(letter);
    }

    bool tf = true;                                 // Pop off the top of each stack and compare
    while (!s.empty()) {                            // them to check for a palindrome
        s.pop(x);
        q.pop(y);
        if (x == y);
        else tf = false;
    }
    if (tf){
        cout << "is a palindrome!" << endl;
    }
    if (!tf) {
        cout << "is NOT a palindrome" << endl;
    }
}

}

2 个答案:

答案 0 :(得分:0)

ABBA

在这里,你一遍又一遍地推着同一个字母。 即使你在评论中重写它也是错误的。

如果您弹出[{1}}的一半,则BAAB并比较B=A 你需要重新思考你的策略。也许将一半字符串推到s然后从length向后循环并推送到q

答案 1 :(得分:0)

就像其他人提到的那样,即使用“q”堆栈修复for循环,一般策略也不正确。实际上你不需要两个堆栈。 (或者甚至是一个堆栈,但如果需要,您可以使用堆栈。)

你有正确的想法将字母的后半部分与前半部分进行比较。一般来说,要找到一个回文,您只需要查看该字符串是否与反向字符串相等,或者前半部分是否等于后半部分。

您可以使用堆栈反向存储字符串。您只需要堆栈和字符串。但是,这里存在额外的问题,即字符串行包含要忽略的空格和标点符号。使用erase()方法可以减少字符串的长度,因此您需要一个临时变量来在堆栈的同时重建格式化的字符串。编辑:我看到你的更新,以减少长度;这很棒 - 它甚至可以节省使用临时变量来保存格式化的字符串,以便只需要变量string line

这是你的while循环的另一个版本,它使用一个堆栈和一个临时字符串变量。它使用一半格式化的字符串来比较堆栈的顶部(表示字符串的“后面”)。

string cleanString;

//cout << "test3";
while (getline(input, line)) {                      // Read the file line-
                                                    //by-line into "line"
    cout << "The line read was: " << line << endl;
    int length = line.length();                     // Sets length equal to
                                                    //string length

    for (int i =0; i<length; i++)                  // Capitalizes string
            line[i] = toupper(line[i]);

    for (int i = 0; i < length; i++)      // Loop through for //every letter in the line
        if ( !(line[i] == ' ' || ispunct(line[i]))) { // Ignore space & punctuation
            letter = line[i];                       // Push each letter onto
            s.push(letter);                            //the stack
            cleanString.push_back(letter);             //and to the "cleaned" string to compare with later
            //cout << cleanString << endl;       //test
        }


    length = cleanString.length();
    bool tf = true;
    for (int i = 0; i < length/2; i++)    {   // Pop off the top of stack
        s.pop(x);                               // to compare with front of string
        if ( cleanString[i] != x ) {   //not a palindrome
            tf = false;
            break;
        }
    }


    if (tf){
        cout << "is a palindrome!" << endl;
    }
    if (!tf) {
        cout << "is NOT a palindrome" << endl;
    }
}

但是完全跳过堆栈的使用更简单,而只是使用临时“已清理”字符串,在带有两个计数器的for循环中检查回文:一个用于前面,一个用于后面。

大写之后:

// Instead of a stack, just build a string of chars to check for a palindrome
for (int i = 0; i < length; i++)      
    if ( !(line[i] == ' ' || ispunct(line[i]))) { 
        letter = line[i];                       // Push each letter onto
        cleanString.push_back(letter);           // a temp string 
    }


length = cleanString.length();  //use length of formatted string
bool tf = true;
int front = 0;       // first char of string
int back = length-1; // last char of string
for (; i < length/2; front++, back--)  
    if ( cleanString[front] != cleanString[back] ) {   //not a palindrome
        tf = false;
        break;
    }

另一个选择是在构建临时字符串后使用reverse()头文件中的内置<algorithm>函数:

#include <algorithm>    // reverse()
string cleanString;
string reversedCleanString;
//...

// Instead of a stack, just build a string of chars to check for a palindrome
for (int i = 0; i < length; i++)      
    if ( !(line[i] == ' ' || ispunct(line[i])))
        cleanString.push_back(line[i]); 

reversedCleanString = cleanString;   // store copy of string to reverse
reverse(reversedCleanString.begin(), reversedCleanString.end() ); // reverse

bool tf = true;
if ( cleanString != reversedCleanString)
    tf = false;
// ...

正如moooeeep提到的那样,使用std :: string的反向迭代器在大写后更进一步简化了这一点:

string cleanString;
//...
// Format line to test if palindrome
for (int i = 0; i < length; i++)      
    if ( !(line[i] == ' ' || ispunct(line[i])))
        cleanString.push_back( line[i] ); 

bool tf = true;
if ( cleanString != string(cleanString.rbegin(), cleanString.rend() )
    tf = false;
// ...

另外,就像moooeeeep所提到的那样,将while循环的不同部分封装到各自独立的函数中是一个好主意,不仅可以简化调试,还可以更直观地理解问题的逻辑流程。

例如,while循环可能如下所示:

while (getline(input, line)) { // Read the file line-by-line into "line"
    //echo input
    cout << "The line read was: " << line << endl;

    // validate/format the line
    extractChars( line );   //remove space/punctuation
    capitalizeString( line );  // capitalize chars for uniformity

    //check if formatted line is a palindrome and output result
    if ( is_palindrome( line ) )
        cout << "Line IS a palindrome << endl;
    else 
        cout << "Line IS NOT a palindrome << endl;
}