上次已经说了句子中的单词逐个逆序,那么,单词内部不变,整个句子逆序又如何呢?面试的时候经常会考到这两题,前者是考思维的缜密,后者是考数据结构(链表)了,当然,不用链表也可以做,我将在一会给大家贴出不用链表的简单方法~
先看题:
将一个句子逆序
例如:
输入:
This is a cat, I like it.
输出:
it. like I cat, a is This
下面这个例子是相对来说比较常规的算法,即将每个单词依次存入链表中,然后将整个链表逆序,再将逆序后的链表中的各个单词取出来,自然是逆序后的句子了。
#include<iostream>
#include<string>
#include<cstdlib>
#include<string>
#include<cassert>
using namespace std;
struct Node
{
string str;
Node * next;
};
bool is_letter(char c)
{
return (isalpha(c)||c == '.'||c==',');
}
void sen_rev(string & str)
{
Node * pHead;
Node * pCur;
pCur = pHead = new Node;
int word_index = 0;
int word_size = 0;
string word_cur;
bool is_first_node = true;
for(int i = 0; i < str.length(); i++)
{
if((i == 0 && str[i] != ' ')||(str[i-1] == ' ' && is_letter(str[i])))
{
word_index = i;
for(int j = i; j < str.length() && is_letter(str[j]); j++)
{
word_size ++;
}
word_cur.resize(word_size);
for(int j = word_index; j < word_index + word_size; j++)
{
word_cur[j - word_index] = str[j];
}
if(is_first_node == false)
{
pCur -> next = new Node;
pCur = pCur -> next;
}
pCur -> str = word_cur;
pCur -> next = NULL;
is_first_node = false;
word_size = 0;
}
}
Node * pNext, * pNextNext;
pCur = pHead;
pNext = pCur -> next;
while(pNext)
{
pNextNext = pNext -> next;
pNext -> next = pCur;
pCur = pNext;
pNext = pNextNext;
}
pHead -> next = NULL;
pHead = pCur;
pCur = pHead;
string result;
while(pCur->next)
{
cout<<pCur->str<<endl;
result += pCur->str;
result += ' ';
pCur = pCur->next;
}
result += pCur->str;
str = result;
return;
}
int main(int argc, char ** argv)
{
string str = "This is a cat, I like it.";
sen_rev(str);
cout << str << endl;
system("pause");
return 0;
}
本例子将标点也算在单词中了,当然读者不喜欢的话可以去掉标点,当然这对于理解整个算法来说并不重要,代码中isalpha( )函数是判断字符是否是大小写字母的函数。
另外,本例中是有坑的:链表的基础是结构,但是结构的存储空间是固定的,然而string是个不定长的东西,怎么办呢?
解决方法如下:
word_cur.resize(word_size);
确定单词长度后,将相应的节点中string 的大小resize一下,变成我们需要的长度,这样的话就可以了,否则在大部分编译器中会报错的哦。
另外,还有一种方法,但这种方法就比较重技巧而轻数据结构了:
#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;
bool is_letter(char c)
{
return (isalpha(c)||c == '.'||c==',');
}
void sen_rev(string & str)
{
string result;
string word_cur;
int word_index = 0;
int word_size = 0;
for(int i = str.size() -1; i >= 0; i--)
{
if((i == str.size() - 1 && str[i] != ' ')||(str[i+1] == ' ' && is_letter(str[i])))
{
word_index = i;
for(int j = i; j >=0 && is_letter(str[j]); j--)
{
word_size ++;
}
word_cur.resize(word_size);
for(int j = word_index; j > word_index - word_size; j--)
{
word_cur[word_size - (word_index - j) - 1] = str[j];
}
result += word_cur;
result += " ";
word_size = 0;
}
}
str = result;
}
int main(int argc, char ** argv)
{
string str = "This is a cat, I like it.";
sen_rev(str);
cout << str << endl;
system("pause");
return 0;
}
可见这段代码的长度比上一段短了很多,思路是从句子末尾开始向前查找单词,找到了就把这个单词放到result追加到字符串的后面,并加一个空格。在句子中从末尾找到开头找出所有的单词,在此过程中,result也生成了,就是我们想要的结果。