提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
这几天做题的时候,遇到了一个很有趣的题目:字符串逆置,注意注意!!!!!一定要注意的是字符串逆置,而不是倒着打印字符串,这两种是有区别的,字符串逆置是改变了原有数组中的元素,而倒着打印字符串并没有改变原有数组中的元素,两者是不可以混淆的,接下来我会用三种方法来向大家展示这道题的做法。
解法一(迭代):
#include<stdio.h>
#include<string.h>
void reverse(char arr[])//函数实现
{
//思路:1.通过下标访问数组第一个元素与最后一个元素,将这两个元素调换,再访问第数组二个元素与倒数第二个元素,再调换他们,以此类推
//下标实现:
int left = 0;
int right = strlen(arr) - 1;//注意这里不能用sizeof(arr),因为这里传过来的arr实质上是这个数组首元素的地址,因此sizeof(arr)是等于4的。
do
{
//元素调换:
char temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
// 2.将左边的下标++,右边的下标--,重复元素调换步骤(循环),一直到中间没有元素可以调换(left<right)
left++;
right--;
} while (left < right);// 注意do while语句在最后一定要写”;”
}
void test01(char arr[])//代码测试实现
{
int len = strlen(arr);
for (int i = 0; i < len; i++)
{
printf("%c ", arr[i]);
}
}
int main()
{
char arr[] = "abcdefg";
reverse(arr);//字符串逆置函数
test01(arr);//测试字符串逆置
return 0;
}
解法二(递归):
1.什么是递归
1.通俗来说就是函数自己调用自己
2.主要思想就是把大事化小
3.递归的解析
递归是一种解决问题的有效方法,在递归过程中,函数将自身作为子例程调用。. 简单说程序调用自身的编程技巧叫递归。. 递归的思想是 把一个大型复杂问题层层转化为一个与原问题规模更小的问题,问题被拆解成子问题后,递归调用继续进行,直到子问题无需进一步递归就可以解决的地步为止 。. 使用递归需要避免出现死循环,为了确保递归正确工作,递归程序应该包含2个属性:. 基本情况(bottom cases),基本情况用于保证程序调用及时返回,不在继续递归,保证了程序可终止。
2.递归的两个必要条件
1.必须存在限制条件,当满足这个限制条件的时候,递归便不再继续。
2.每次递归调用后越来越接近这个限制条件(否则将会死递归,最后造成栈溢出)。
3.递归解法错误示范
#include<stdio.h>
#include<string.h>
void reverse(char* arr)//本质传递的是地址,所以用指针接收
{
//思路:将g与a交换,然后逆序"bcdef"这个字符串,再将b与f交换,然后逆序"cde"这个字符串,以此类推直到中间只剩下一个字符'd'(strlen(arr)>=2)就成功逆序了
int left = 0;
int len = strlen(arr);
char temp = *arr;//将a存入一个变量
*arr = *(arr + len - 1);//交换
*(arr + len - 1) = '\0';//变成gbcdef这个字符串。注意只有斜杠0结尾的称之为字符串,所以要进行赋值
reverse(arr + 1);//逆序bcdef
*(arr + len - 1) = temp;//将*arr放到最后一个元素
}
void test02(char arr[])//测试代码实现
{
for (int i = 0; i < strlen(arr); i++)
{
printf("%c ", arr[i]);
}
}
int main()
{
char arr[] = "abcdefg";
reverse(arr);
test02(arr);//测试代码
}
4.递归解法错误示范解析
1.上面说堆栈溢出了,原因就是因为死递归了,函数一直自己调用自己,我们都只知道函数是在栈区开辟内存的,一直调用的话,总有挤满栈区的一天,所以我们应该在这个函数自己调用这个函数的时候给它一个限制条件。
2.我们一直常说递归的条件一个是必须存在限制条件,当满足这个限制条件的时候,递归便不再继续,一个是在每次递归调用后越来越接近这个限制条件(否则将会死递归,最后造成栈溢出),那么这个的限制条件是什么呢?我们可以来分析一下:
首先这个函数的功能是逆序字符串,那么等到什么时候就不用逆序了呢,答案显然是:你要逆序的字符串只剩下一个字符了,那就不用再逆序了,所以我们的限制条件是strlen(arr+1)>=2。
5.递归解法正确示范
#include<stdio.h>
#include<string.h>
void reverse(char* arr)//本质传递的是地址,所以用指针接收
{
//思路:将g与a交换,然后逆序"bcdef"这个字符串,再将b与f交换,然后逆序"cde"这个字符串,以此类推直到中间只剩下一个字符'd'(strlen(arr)>=2)就成功逆序了
int len = strlen(arr);//字符串的长度
char temp = *arr;//将a存入一个变量
*arr = *(arr + len - 1);//交换第字符串中第一个元素与最后一个元素
*(arr + len - 1) = '\0';//变成gbcdef这个字符串。注意只有斜杠0结尾的称之为字符串,所以要进行赋值
if (strlen(arr+1)>=2)
reverse(arr + 1);//逆序bcdef
*(arr + len - 1) = temp;//将*arr放到最后一个元素
}
void test02(char arr[])//测试代码实现
{
for (int i = 0; i < strlen(arr); i++)//遍历数组
{
printf("%c ", arr[i]);
}
}
int main()
{
char arr[] = "abcdefg";
reverse(arr);
test02(arr);//测试代码
}
总结
1.在做这类型题时首先要认真审题,上面要求的是要逆序这个数组中的每个元素,意思就是让你改变原有的数组。
2.调用递归时必须要写限制条件!!!!!!
写上不一定对,但是不写一定是错的!!!!!
3.怎样写出递归:要看你这个函数实现的是什么功能,它是被整体包装过的,不要在意它里面的细节,要看整体流程,就拿这个例子来说,我们的目的是要把"abcdefg"这个字符串逆序,那么这个函数的功能也就确定了,就是字符串逆序,只要你给我一个字符串,我就能把你给逆序过来,那么这个字符串就可以这样理解:先把a保存起来,让g赋给a,然后再逆序bcdef这个字符串,逆序过来之后,再让保存a的那个值赋给最后一个元素。