递归算法-字符串反转

  1. 前言

递归算法对解决重复的子问题非常有效,字符串反转也可以用递归算法加以解决,递归算法设计的关键是建立子问题和原问题之间的相关性,同时需要确立递归退出的条件;如果递归退出的条件无法确定,那么就会出现爆栈的错误(stack overflow)。

  1. 问题描述

给定某个字符串,word=“hello”,通过递归算法实现反转,输出"olleh"字符串。对于递归算法的实现,可以有两种不同的思路,其一是创建一个新的字符串变量,用于保留反转后的字符串;其二是对原字符串直接进行反转,无需借助新的字符串变量。

  1. 子问题分析和递归结束结束条件

对于字符串word=“hello”,其子问题可以通过不断降低字符串长度,从而减低字符的数量。对于字符串word,我们可以构建如下子问题,

word=“hello” 作为原始问题,

word="ello"作为第一个子问题,

word="llo"作为子问题的子问题,

word="lo"作为子问题的子问题的子问题,

word="o"作为子问题的子问题的子问题的子问题–递归结束条件;

word=""空串–递归结束条件

通过上面分析,我们可以选择空串作为递归结束条件,或者选择长度为1的串作为递归结束条件。对于问题描述当中提到两种不同思路,它们分别采用不同的递归结束条件,其中一个方法选择空串作为结束条件,原地反转选择长度为1的子串作为递归的结束条件。

  1. 借助全新字符串变量的递归算法

设计递归函数f(char *word, char *reversal_word, int *i),三个变量分别代表原始字符串,反转后的字符串以及记录反转字符串的下标i.

过程中,我们利用word变为空串时候作为结束条件,在递归返回的时候,提取当前word的首字符,然后保存到reversal_word的第i个字符地址中。

为了更方便理解递归过程,采用图示的方式辅助理解,递归永远都是有去有回,这是由栈的性质决定的,因为程序执行的过程有入栈就必须有出栈,只有这样程序才能完整执行。

当遇到空字符的时候,这时候递归需要结束,开始返回,代表开始出栈的过程。

出栈过程中,我们利用word的当前状态,对reversal_word[i]赋值当前的word[0],最终完成源字符串的反转。

  1. 借助全新字符串变量的递归代码实现

递归的过程非常简单,每次把word的指针往前推进1,直至遇到空字符,然后进行回退。

//*i will be set 0 as intial value
void reverse_word(char *word, char *reversal_word, int *i)
{char ch;if(*word=='\0'){return;}else{reverse_word(word+1,reversal_word,i);reversal_word[(*i)++] = *(word + 0);}
}

在递归过程中,很容易出现一类错误的算法,这里需要提别提醒,希望引起大家的注意,假定把递归体里面的代码更新成如下格式,好像没有什么错误,但是返回的reversal_word的结果为{‘\0’,‘o’,‘l’,‘l’,‘e’,‘\0’}仔细分析过程,从C语言角度理解,因为首字符为’\0’,它等同于空串。

为什么会出现这种情况呢? 其实道理很简单,原因在于每次word的回退,它其实都提前了一个节拍,因为在递归前word的值已经发生改变,正确的递归中,word+1只是把指针往前推进一步(具体为sizeof(char)字节),但是当word回退的时候,其word的值仍然和递归入口 处的值保持一致。

else
{word=word+1;reverse_word(word,reversal_word,i);reversal_word[(*i)++] = *(word + 0);
}
  1. 自身反转的递归算法

字符串反转,如果不考虑保留原来的字符串,可以借助字符串本身,对其收尾字符进行有效交换,从对原有字符串完成反转。具体原理就是中间字符视作支点,完成两端字符的交换,这个过程可以借助递归完成。其递归的出口是对字符串的长度进行相应的判断,如果长度减少到1,那么就可以出栈,递归可以掉头返回。

具体来看一下示意图,过程中完成三步操作,在指针往前移动之前,先保留指针指向的字符,然后再交换首字符和末端字符,最后把当前的尾字符赋值为空’\0’,一切完成后,把指针往前推进一步。后面不断重复上面的步骤,直至字符串的长度为1,开始回退(递归出口)

入栈过程

出栈过程

  1. 自身反转的代码实现

    当字符串的长度等于1的时候,也就是已经到了原字符串的支点,这个点就是递归的出口,如果再继续反转下去,那么过程结束的时候,又回到原有的状态。

    这个过程中,ch保留首字符是代码成功实现的关键,当递归回退的时候,我们需要利用到递归前保留的ch首字符值,值得一提的是,每个递归中ch属于不同的变量地址,这一点非常关键;另外对于len的长度值的保留的道理也一样,每个递归中的len都属于不同的变量地址。

void reverse_word_2(char *word)
{int len;char ch;len=strlen(word);if(len<=1){return;}else{ch=*(word+0);*(word+0)=*(word+len-1);word[len-1]='\0';reverse_word_2(word+1);word[len-1]=ch;return;}
}
  1. 小结

大量数据结构和算法的实现都依赖递归,无论是深度优先搜索(DFS)还是动态规划(Dynamic programming),其算法的实现都与递归息息相关。本文采用两种不同的思路,借助递归算法对字符串完成反转,更清晰理解了递归的具体过程和基本原理。

其实递归的本质就是分而治之,大事化小,小事化了,从最基础的子问题倒退建立解的过程。

递归算法_字符串反转_20230412相关推荐

  1. 字符串切片反转字符串_如何反转字符串

    字符串切片反转字符串 Can you write a function that reverses an inputted string without using the built-in Arra ...

  2. java输入一串字符串反转_反转Java中的字符串

    java输入一串字符串反转 Reverse a String in java is a good coding related interview question. I have seen inte ...

  3. python将一个字符串反转并输出_逆转字符串—输入一个字符串,将其逆转并输出。...

    实现Python字符串反转有4种方法: 1.列表的方式: def rev(s): a = list(s) a.reverse() return (''.join(a)) a = rev('huowuz ...

  4. python对输入的字符串进行解析_python数据类型_字符串常用操作(详解)

    这次主要介绍字符串常用操作方法及例子 1.python字符串 在python中声明一个字符串,通常有三种方法:在它的两边加上单引号.双引号或者三引号,如下: name = 'hello' name1 ...

  5. python加密字符串小写字母循环后错两位_python数据类型_字符串常用操作(详解)

    这次主要介绍字符串常用操作方法及例子 1.python字符串 在python中声明一个字符串,通常有三种方法:在它的两边加上单引号.双引号或者三引号,如下: name = 'hello' name1 ...

  6. 字符串反转python_python字符串反转的四种方法详解

    这篇文章主要介绍了python字符串反转的四种详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.用reduce函数方法 book = 'Pyt ...

  7. java案例——字符串反转

    java案例--字符串反转 1.需求: 定义一个方法,实现字符串反转.键盘录入一个字符串,调用该方法后,在控制台输出结果 例如,键盘录入abc,输出结果cba 2.思路: 1.键盘录入一个字符串,用S ...

  8. 字符串-字符串反转(双指针)

    题意: 编写一个函数,其作用是将输入的字符串反转过来.输入字符串以字符数组 char[] 的形式给出. 不要给另外的数组分配额外的空间,你必须原地修改输入数组.使用 O(1) 的额外空间解决这一问题. ...

  9. 编写字符串反转函数 - 小小外星人的技术博客 - 博客频道 - CSDN.NET

    编写字符串反转函数 - 小小外星人的技术博客 - 博客频道 - CSDN.NET 编写字符串反转函数 分类: 笔试面试题 2010-11-07 20:47 863人阅读 评论(0) 收藏 举报 首先用 ...

最新文章

  1. 操作系统的进程状态变迁图_1.操作系统是干什么的?
  2. Python3 基础学习笔记 C09【文件和异常】
  3. yolov5搭建环境_Yolov5环境配置和训练私有数据,YOLOv5,以及,私人
  4. 《PWA实战:面向下一代的Progressive Web APP》读书笔记
  5. 点阵字体显示系列之一:ASCII码字库的显示
  6. 【jQuery笔记Part1】05-jQuery解决冲突
  7. 李开复:一切靠命运或靠自己都是不合适的
  8. tomcat8.5配置优化
  9. 51单片机C语言堆栈,《单片机C语言试题》(一)20101027
  10. kubernetes 查看所有namespace、默认的namespace
  11. hardfault常见原因_STM32如何查找hardfault原因
  12. java项目实体类方法找不到_报错,居然找不到实体类
  13. NGINX负载均衡与本地路径映射
  14. LaTeX--简易教程--论文写作神器
  15. vue中父组件传图片路径src给子组件无法正常显示图片
  16. 当你的工作==你热爱的事情,是一种什么体验?
  17. 神经网络系统图片高清,神经网络系统图片结构
  18. SAPnbsp;PAnbsp;共享nbsp;免费下载
  19. 电荷放大器的Matlab仿真
  20. (Win8、Win7)MAK激活密钥分享【资源有限】

热门文章

  1. 纵览各国关键信息基础设施配套网络安全法规建设
  2. 声纹识别之说话人验证speaker verification
  3. 使用deno和oak开发的短链系统2.0
  4. 信奥中的数学:加法原理和乘法原理
  5. 比较好用的CDN加速节点
  6. 淘汰了80%的Android面试者,搞懂这些直接来阿里入职
  7. 4.4 赋值运算符,4.5 递增和递减运算符
  8. rtk服务器协议,南方rtk服务器地址和端口
  9. Oracle LiveLabs实验:DB Security - Oracle Label Security (OLS)
  10. 如何在Word中创建和打印标签