这道题真的难倒过我......
快要期末考试了,时间比较紧,但是真的忍不住不写博客。
据说,写博客会上瘾,似乎体会到了......
那倒是希望上瘾,然后成为一个博客控。
目录
一、问题描述
将一句话的单词进行倒置,标点不倒置。
比如 I like beijing. 经过函数后变为:beijing. like I
二、算法分析
不同于简单逆序,而是虽然顺序变了,但是每个单词还是完整的单词。我们可以将整个字符串逆序,然后再将每个单词逆序一下
再次强调,我们要做的是这两步:
第一步,逆序整个字符串;
第二步,逆序每个单词。
我们可发现,倒序整个字符串和倒序一个单词的思路大体上是一样,都是从起始位置和结束位置开始逐个一对一对地进行交换。如下图所示,I like beijing.的逆序和like的逆序:
三、算法设计
(1)逆序整个字符串
现定义一个函数,创建两个形参,分别为char* start和char* end,用于记录起始位置和结束位置的字符所在地址。
相应地,这里要把一个字符串的首地址和最后一个字符的地址传递给函数。
字符串首地址用数组名即可,那么末位字符串地址可以用数组名加上字符串长度(可用strlen实现)再减去1。
当传递的地址进入函数内部后进行交换,然后依次让start向右移动,让end向左移动,再交换字符,直到start所指向的字符和end所指向的字符相同时停止交换。
void reverse(char* start, char* end);
char input[100];
gets(input);
reverse(input, input + strlen(input) - 1);
注意不能使用scanf!scanf遇空格结束,要用gets。
接下来用while语句和临时变量实现逆序
while(start < end)
{
char temp = *start;
*start = *end;
*end = temp;
start++;
end--;
}
(2)逆序单词
(事实上,逆序单词和逆序字符串的顺序是可以互换的。
创建两个字符型地址变量,char* cur和char* start,分别记录单词首元字符的地址和末位字符的地址。
调用while函数,条件为当cur所指向地址的字符不为空格并且所指向地址的字符不为\0。
char* cur = arr;
char* start = cur;
while(*cur!=' '&&*cur!='\0')
{
cur++;
}
先前定义过字符串逆序的函数,在逆序一个单词时同样可调用此函数。
当停止循环时,cur指向的是空格,那么在调用函数时就要减去1。
reverse(start,cur-1);
在调用过此函数后,让cur自增,跳过空格。
若想继续进行下去,直到每个单词都实现逆序,就要把刚才所写代码嵌套在while语句中,条件为*start,即当start所指向地址的字符不为\0。
while(*start)
{
char *cur = start;
while(*cur!=' '&&*cur!='\0')
cur++;
reverse(start, cur-1);
cur++;
}
实际上,代码还没完善,当字符串以空格结尾时,循环就会继续进行下去,所以需要给cur自增添加一个cur所指向的地址的字符不为\0的条件。
while(*start)
{
char *cur = start;
while(*cur!=' '&&*cur!='\0')
cur++;
reverse(start, cur-1);
if(*cur!='\0')
cur++;
}
这样就完美了。
四、代码实现
#include <stdio.h>
#include <string.h>
void reverse(char* start, char* end)
{
while(start < end)
{
char temp = *start;
*start = *end;
*end = temp;
start++;
end--;
}
}
int main()
{
char input[100];
// 注意不能使用scanf,scanf遇到空格,一次输入接收就结束了
gets(input);
// 翻转整个句子
reverse(input, input + strlen(input) - 1);
// 翻转单词
char* start = input;
while(*start)
{
char *cur = start;
while(*cur != ' ' && *cur!='\0')
cur++;
reverse(start, cur-1);
if(*cur!='\0')
cur++;
}
printf("%s", input);
return 0;
}