单词逆序算法

如何对一个字符串进行就地逆序,例如: 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;  

    }  


附自编代码一份:

// 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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值