我正在尝试制作一个程序,使用堆栈(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;
}
}
}
答案 0 :(得分:0)
ABBA
在这里,你一遍又一遍地推着同一个字母。 即使你在评论中重写它也是错误的。
如果您弹出[{1}}的一半,则BA
和AB
并比较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;
}