剑指offer--空格的替换

        在学习文件操作的过程中遇到过这样一个问题,比如说我在文件中输入“hello world,10,60.0”,想在屏幕上将其打印出来,然而结果并不是想象中的那样...

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
void test2(FILE *pf)
{
	char buf[20] = {0};
	int d = 0;
	float f = 0.0f;
	fscanf(pf, "%s %d %f", buf, &d, &f);
	printf("%s %d %f\n", buf, d, f);
}
int main()
{
	FILE *pf = fopen("file.txt", "r");
	if(pf == NULL)
	{
		perror("error");
		exit(EXIT_FAILURE);
	}
	test2(pf);
	fclose(pf);
	system("pause");
	return 0;
}


       看到这样的结果很是让人意外,为什么呢?经过仔细分析才发现编译器对字符串的读取方式是当读到空格后将不在往后读取,因此产生了上面的结果,只有将fscanf(pf, "%s  %d  %f", buf, &d, &f);这行代码中格式控制中的空格去掉才能输出想要的结果,为了更好的解决类似的这种问题“空格的替换”就派上了用场。其实在网络编程中,如果URL参数中含有特殊字符,如:空格,'#'等,可能导致服务器无法获得正确的参数值。我们需要将这些特殊符号转换成服务器可以识别的字符。转换的规则是在'%'后面跟上ASCII码的两位十六进制的表示。

比如:空格的ASCII码是32,即十六进制的0x20,因此空格被替换成“%20”。

剑指offer面试题4是这样的:

题目:请实现一个函数,把字符串中的每个空格替换成“%20”。例如:输入“We are happy.”,则输出“We%20are%20happy.”

对于这样一个题而言,其实算法还是挺多的:

(1)对字符串进行遍历,找到空格处,然后将空格后的字符依次向后移动两个字节,再将‘%’‘2’‘0’字符插入,看下图


         假设字符串的长度是n,对每个空格字符需要移动后面O(n)个字符,因此对含有O(n)个空格的字符串而言总的时间效率是O(n^2),显然按照效率来讲的话,这肯定不是最优解!!!

(2)这种算法主要思想就是在计算好空格的基础上为其开辟一块内存空间,非空格字符直接进行复制,空格字符直接放入‘%’‘2’‘0’,算法是挺简单的,但是既然空格都统计出来了,我们为何不通过指针来解决呢,重新开辟空间多浪费啊。

(3)通过以上算法分析我们给出一种比较高效的.

@统计好空格后计算出替换之后字符串的总长度;

@让一个指针p1指向原始字符串的末尾,另一个指针p2指向替换之后字符串的末尾;

@接下来向前移动p1,将其指向的非空格字符直接复制到p2的位置(如下图所示,灰色部分进行了字符串的拷贝),遇见第一个空格时,把p1向前移动一格,p2向前移动3格并插入‘%’‘2’‘0’。然后接着向前复制,直到遇见空格,将p1移动1格,p2移动3格并插入‘%’‘2’‘0’,直至p1,p2指向同一位置。

从上面的分析来看,所有字符都只移动,复制一次,因此比起第一种这个效率还是挺高的。

下面给出代码:

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
void ReplaceBlack(char arr[],int len)
{
	int count=0;      //记录空格数
	int oldlen=len;   //起初arr[oldlen]指向字符串的末尾
	int newlen=0;
	char *ptr=arr;
	if(arr==NULL && len<=0)
	{
		return;
	}
	while(*ptr)            //统计出空格数
	{
		if(*ptr==' ')
		{
			count++;
		}
			ptr++;
	}
	newlen=oldlen+2*count;    //求得插入%20后的总长度
	while(oldlen<newlen)
	{
		if(arr[oldlen]!=' ')   
		{
			//原字符串中没有空格时字符向后移动
			arr[newlen--]=arr[oldlen--];  
		}
		else
		{ 
			//防止内存覆盖
			arr[newlen--]='0';
			arr[newlen--]='2';
			arr[newlen--]='%';
			oldlen--;
		}
	}
}
int main()
{
	char str[20]="We are happy.";
	int len=0;
	len=sizeof(str)/sizeof(str[0])-1;
	ReplaceBlack(str,len);
	printf("%s\n",str);
	system("pause");
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值