如何对一个字符串进行就地逆序,例如: This is a test
逆序以后变为: tset a si sihT
这个问题很简单,我们可以先获取字符串的长度,假设为n,那么我们可以进行一系列的交换:
0 – n-1
1 – n-2
……..
n/2
当然,这里面还涉及到一个就地逆序的问题,交换的时候不可以开辟内存空间,关于这个问题我们已经讨论过,请参考:
就地交换两个数
okay,问题解决了,我们把问题变一下:
如何对一个字符串中的单词进行逆序,例如: This is a test
单词逆序后变成: test a is This
好像有点棘手了? 如果我们仔细观察下,两种逆序的结果:
tset a si sihT
test a is This
我们发现,单词逆序的结果,实际上是把字符串逆序以后,再把每个单词逆序一下,就可以了。那么问题就简单了,为了实现单词逆序,我们可以使用这样的一种函数形式:
查看源代码打印帮助void reverse(const char* str, int start, int len);
其参数的意义分别如下:
str: 需要处理的字符串
start: 逆序开始的位置, 如果从第一个字符开始逆序,则应当填入0
len : 需要逆序的字符串的长度,如果到最后一个字符结束,则需要strlen(str)求的字符串长度
为了使这个函数发挥最大功能,我们不对字符串长度进行校验。也就是说,我们逆序的时候,可以包含字符串的结尾: \0
以下是 reverse 以及 word_reverse 的实现:
查看源代码打印帮助// 首先我们做一个就地交换两个数的函数,如果有不明白的请参考文章开头提到的参考文章
void switch_in_place(char* a, char* b)
{
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
}
// 开始字符串的逆序
void reverse(const char* str, int start, int len)
{
// 找到交换的中间点位置,不需要关心 end的奇偶问题,如果是偶数,那是正好,
// 如果是奇数,则最中间那个数是无需交换的
int middle_pos = start + len / 2;
for (int i=start; i<middle_pos; i++)
{
// i 对应的交换位置应该是 i + 2 * (middle_pos - i)
switch_in_place(&str[i], &str[2* middle_pos - i]);
}
}
// 对单词进行逆序:
void word_reverse(const char* str)
{
// 对输入参数进行校验
if (str == NULL)
{
return;
}
// 首先我们需要知道字符串的长度
int len = strlen(str);
// 整体逆序
reverse(str, 0, len);
// 对空格进行分析,然后逆序
int reverse_start = 0; // 逆序开始位置
int reverse_end = 0; // 逆序结束位置
int reverse_len = 0; // 要逆序的字符串的长度,由 reverse_end - reverse_start得出
// 对每一个单词进行逆序,
while (reverse_start < len)
{
// 寻找一个单词的起点,也就是第一个不为空格的字符
while(reverse_start < len && str[reverse_start] == ' ') reverse_start++;
// 寻找单词的终点,也就是第一个为空格的字符
reverse_end = reverse_start;
while(reverse_end < len && str[reverse_end] != ' ') reverse_end++;
// 计算要逆序的长度,逆序字符串从 reverse_start开始,到reverse_end,但不包括reverse_end
reverse_len = reverse_end - reverse_start;
// 逆序
reverse(str, reverse_start, reverse_len);
// 更新 reverse_start
reverse_start = reverse_end;
}
逆序以后变为: tset a si sihT
这个问题很简单,我们可以先获取字符串的长度,假设为n,那么我们可以进行一系列的交换:
0 – n-1
1 – n-2
……..
n/2
当然,这里面还涉及到一个就地逆序的问题,交换的时候不可以开辟内存空间,关于这个问题我们已经讨论过,请参考:
就地交换两个数
okay,问题解决了,我们把问题变一下:
如何对一个字符串中的单词进行逆序,例如: This is a test
单词逆序后变成: test a is This
好像有点棘手了? 如果我们仔细观察下,两种逆序的结果:
tset a si sihT
test a is This
我们发现,单词逆序的结果,实际上是把字符串逆序以后,再把每个单词逆序一下,就可以了。那么问题就简单了,为了实现单词逆序,我们可以使用这样的一种函数形式:
查看源代码打印帮助void reverse(const char* str, int start, int len);
其参数的意义分别如下:
str: 需要处理的字符串
start: 逆序开始的位置, 如果从第一个字符开始逆序,则应当填入0
len : 需要逆序的字符串的长度,如果到最后一个字符结束,则需要strlen(str)求的字符串长度
为了使这个函数发挥最大功能,我们不对字符串长度进行校验。也就是说,我们逆序的时候,可以包含字符串的结尾: \0
以下是 reverse 以及 word_reverse 的实现:
查看源代码打印帮助// 首先我们做一个就地交换两个数的函数,如果有不明白的请参考文章开头提到的参考文章
void switch_in_place(char* a, char* b)
{
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
}
// 开始字符串的逆序
void reverse(const char* str, int start, int len)
{
// 找到交换的中间点位置,不需要关心 end的奇偶问题,如果是偶数,那是正好,
// 如果是奇数,则最中间那个数是无需交换的
int middle_pos = start + len / 2;
for (int i=start; i<middle_pos; i++)
{
// i 对应的交换位置应该是 i + 2 * (middle_pos - i)
switch_in_place(&str[i], &str[2* middle_pos - i]);
}
}
// 对单词进行逆序:
void word_reverse(const char* str)
{
// 对输入参数进行校验
if (str == NULL)
{
return;
}
// 首先我们需要知道字符串的长度
int len = strlen(str);
// 整体逆序
reverse(str, 0, len);
// 对空格进行分析,然后逆序
int reverse_start = 0; // 逆序开始位置
int reverse_end = 0; // 逆序结束位置
int reverse_len = 0; // 要逆序的字符串的长度,由 reverse_end - reverse_start得出
// 对每一个单词进行逆序,
while (reverse_start < len)
{
// 寻找一个单词的起点,也就是第一个不为空格的字符
while(reverse_start < len && str[reverse_start] == ' ') reverse_start++;
// 寻找单词的终点,也就是第一个为空格的字符
reverse_end = reverse_start;
while(reverse_end < len && str[reverse_end] != ' ') reverse_end++;
// 计算要逆序的长度,逆序字符串从 reverse_start开始,到reverse_end,但不包括reverse_end
reverse_len = reverse_end - reverse_start;
// 逆序
reverse(str, reverse_start, reverse_len);
// 更新 reverse_start
reverse_start = reverse_end;
}
}
附自编代码一份:
// reverse.cpp
/********************************************
Author : Walker
Time : 2010-12-03
*********************************************/
//
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#define SPACE 0X20
#define END 0X00
int strlength(const char * );
char * check(char * );
//词逆序处理函数
const char * reverse(const char * p_input)
{
if(p_input == NULL)
{
return NULL;
}
size_t con_size = strlength(p_input);
//申请两份通输入字符串同长内存
char * sz_a = (char *)malloc(con_size + 1);
char * sz_b = (char *)malloc(con_size + 1);
char * p_head = 0;
char * p_tail = 0;
char * p_end = 0;
memset(sz_b, 0, con_size + 1);
memcpy(sz_a, p_input, con_size+1);
p_head = sz_a;//指向sz_a空间首地址
p_end = sz_b + con_size;//指向sz_b空间尾地址
while(*p_head != END)
{
//获取空格或结尾符所在地址
p_tail = check(p_head);
p_end--;
//根据获取的空格或结尾符所在地址,依次往前获取各个字符从sz_b空间尾地址写入
for (char * p_i = p_tail;p_i != p_head ; )//考虑第一次就为空格的情况
{
p_i--;
*p_end = *p_i;
p_end--;
}
*p_end = SPACE;
p_head = ++p_tail;
}
delete sz_a;
return sz_b;
}
//求字符串长度
int strlength(const char * s)
{
int len = 0;
while(*s)
{
len++;
s++;
}
return len;
}
//获取空格和结尾符的内存地址
char * check(char * p_compare)
{
if(SPACE == *p_compare ||END == *p_compare)
return p_compare;
else
p_compare++;
return check(p_compare);
}
int _tmain(int argc, _TCHAR* argv[])
{
char * ss1 = 0;//" this is a \nbook \n and p\n";
const char * ss2 = reverse(ss1);
printf("reverse string is[%s]\n",ss2);
return 0;
}