目录
一、题目描述
编写一个函数reverse_string(char *string)(递归实现)
实现:将参数字符串中的字符反向排列,不是逆序打印。
要求:不能使用C函数库中的字符串操作函数。
比如:char arr[] = "abcdef";
主要目的就是考虑如何使用递归实现字符串中的字符反向排列;使对递归函数有一个更深层次的理解。
大体的思路可以用下面的代码展示;问题的关键就是如何写出reverse_string()函数。
#include<stdio.h>
int main()
{
char arr[] = "abcdef";
reverse_string(arr);
printf("%s", arr);
return 0;
}
二、分析思路
把步骤分为两步走;第一步先先考虑使用循环来实现;第二步考虑怎么转化为递归;归结起来就是在使用了循环实现之后,转换为递归实现。在实先过程中会用到Strlen()函数,总结如下:
三、Strlen()函数的实现
其实Strlen()函数的实现有很多方式,既可以考虑使用循环实现,也可以考虑使用递归来实现;
先给出Strlen()函数的实现过程;方便后面使用:
用循环实现Strlen()函数:
int Strlen(char* arr)
{
int count = 0;
while (*(arr) != '/0')
{
count++;
arr++;
}
return count;
}
*arr找到arr数组对应的元素,然后判断是否为\0,不是就把地址+1;继续判断;在此过程需要一个变量count记录每往后一次判断的次数。
用递归实现Strlen()函数
int Strlen(char *arr)
{
if (*(arr) != '\0')
{
return 1 + Strlen(1 + arr);
}
else
{
return 0;
}
}
四、循环实现reverse_string
要实现交换很简单,只需要实现a与f交换,b与e交换,c与d交换就可以;假设a的下标为left;f的下标为right; 通过下标实现将a与f交换,然后left++;right--实现单次交换;然后停下来的条件是下标left 大于等于right; 等于情况时,只有一个元素,交不交换都可以;在这里知道right下标需要知道arr数组长度,用自己写的Srlen()函数实现;因为题目说了不能使用c语言中的库函数。
void reverse_string(char* arr)
{
int left = 0;
int right = Strlen(arr) - 1;
while (left < right)
{
char tmp = *(arr + left);
*(arr + left) = *(arr + right);
*(arr + right) = tmp;
left++;
right--;
}
}
其实while循环里面有另外一种写法和上述写法等价;如下:
void reverse_string(char* arr)
{
int left = 0;
int right = Strlen(arr) - 1;
while (left < right)
{
char tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
两种方法说明:*(arr+left)等价于arr[left];
在这里说一下reverse_string的形参部分;实参用数组名作为参数,数组名是数组首元素的地址,在这里形式参数用指针接收地址,完全符合逻辑,没有任何问题的
另外一个角度来说;要对arr这个数组进行修改之后在打印,采用传址调用;也是没有问题的
但是这里本质上还是指针
这里可以写为char arr[]:因为实参是数组,传给形参时候,形参用数组接收实参传来的数组,是可行的;代码就如下面所示了:
void reverse_string(char arr[])
{
int left = 0;
int right = Strlen(arr) - 1;
while (left < right)
{
char tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
此处不可以换成sizeof()来计算arr;因为sizeof(arr)表示计算arr这个指针变量的大小(32位平台指针大小为4个字节;64位平台为8个字节);right值就为3了。
这里注意点是形式参数里面的arr与main函数里面的arr不是同一个,因为形参变量可以与实参变量相同,建议为避免混淆,尽量不同为妙;
五、递归实现reverse_string
在使用递归来实现字符串中字符交换时;其他部分大体相同,不同之处就在于reverse_string()函数的实现;针对本题 递(传递)归(回归)思想:
要实现字符串a b c d e f \0的逆序步骤;
1、交换a与f,再使用reverse_string()函数逆序bcde
2、bcde可以再次分为交换b和e,然后使用reverse_string()函数逆序cd
3、cd可以再次分为交换c和d,然后使用reverse_string()函数逆序空字符串(什么都没有了)
但是这样是有错误的,先实现大体框架,后面再修改吧(先把框架搭起来,然后再此基础上面慢慢修改)
void reverse_string(char* arr)
{
int length = Strlen(arr);
char tmp = *(arr);
*(arr) = *(arr + length - 1);
*(arr + length - 1) = tmp;
reverse_string(arr + 1);
}
但是这里这样写是有问题的,因为如果逆序完a与f之后,字符串变为fbcdea \0
再进行逆序,程序就以为你要逆序bcdea; 所以在执行*(arr)=*(arr+length-1)之后,应该暂时给
*(arr+length-1)='\0'; 然后执行下一次逆序reverse_string(arr + 1);最后把执行
*(arr+length-1)=tmp 也就是应该这样来写:
char tmp = *arr;
int length = Strlen(arr);
*arr=*(arr+length-1);
*(arr+length-1)='\0';
reverse_string(arr + 1);
*(arr+length-1)=tmp;
但是还是有个问题:reverse_string()里面又套了一个reverse_string();递归没有限制条件,会一直死循环递归下去; 所以第二个reverse_string()处应该加上条件(中间递归的字符串个数要大于2);所以要在reverse_string()前面加上if(Strlen(arr+1));结果如下:
char tmp = *arr;
int length = Strlen(arr);
*arr=*(arr+length-1);
*(arr+length-1)='\0';
if(Strlen(arr+1) >= 2)
{
reverse_string(arr + 1);
}
*(arr+length-1)=tmp;
这样就使用递归解决了字符串中字符的交换。
六、代码展示
下面给出递归实现的整个演示过程:
循环实现的总过程:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int Strlen(char* arr)
{
if (*(arr) != '\0')
{
return 1 + Strlen(1 + arr);
}
else
{
return 0;
}
}
void reverse_string(char* arr)
{
int left = 0;
int right = Strlen(arr) - 1;
while (left < right)
{
char tmp = *(arr + left);
*(arr + left) = *(arr + right);
*(arr + right) = tmp;
left++;
right--;
}
}
int main()
{
char arr[] = "abcdef";
reverse_string(arr);
printf("%s", arr);
return 0;
}
递归实现的总过程:
#include<stdio.h>
int Strlen(char* str)
{
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
void reverse_string(char* str)
{
int left = 0;
int right = Strlen(str) - 1;
char tmp = *(str+left);
*(str + left) = *(str + right);
*(str + right) = '\0';
if(Strlen(str)>=2)
{
reverse_string(str + 1);
}
*(str + right) = tmp;
}
int main()
{
char arr[] = "abcdef";
reverse_string(arr);
printf("%s", arr);
return 0;
}