设为首页 加入收藏

TOP

2.3 执行动作的递归(1)
2014-03-11 13:05:03 来源: 作者: 【 】 浏览:137
Tags:2.3 执行 动作

2.3  执行动作的递归(1)

递归函数不一定要返回值,可以是void函数。

递归void函数:逆置字符串

现考虑一个稍复杂的问题:给出一个由字符组成的字符串,将其逆序排列。例如,将字符串"cat"写为"tac"。要创建递归解决方案,需要回答2.1节末尾的提示中给出的4个问题。

可根据长度为n-1的字符串的逆置问题,来创建长度为n的字符串逆置问题的解决方案。换句话说,解决方案的各个递归步骤将要逆置的字符串的长度减1。字符串越来越短这个事实表明:一些非常短的字符串的问题可用作基例。最短的字符串是空字符串,其长度为0。可将问题的基例选择为:

逆置空字符串

注释:基例

基例的解决方案简单明了:什么都不用做(此外也可将长度为1的字符串用作基例)。

究竟如何用长度为n-1的字符串逆置问题的解决方案,来解决长度为n的字符串逆置问题呢?这与创建阶乘问题解决方案所用的方法类似,即用factorial(n-1)来计算factorial(n)。但又与阶乘问题不同,这个字符串问题并不存在一个直接明了的推进方法。很明显,并不是所有长度为n-1的字符串都能解决问题。例如,逆置"apple" (长度为5的字符串)与逆置"pear" (长度为4的字符串)之间没有关系。必须精心选择更小的问题,以将其解决方案用于原始问题的解决方案。

注释:如果可以将n-1个字符的字符串逆置,如何才能将n个字符的字符串逆置呢

所选的长度为n-1的字符串必须是原始字符串的一部分,即子串。假设从原始字符串去掉一个字符,留下长度为n-1的子串。为使递归解决方案有效,逆置子串的功能与其他辅助功能相组合,必须能够实现原始字符串的逆置。将这个方法与递归计算factorial的方法进行比较:计算factorial(n-1)的功能与将该值乘以n的功能组合,才具有计算factorial(n)的功能。

需要判断去掉的字符以及要执行的辅助任务。先考虑辅助任务。因为要输出字符,所以辅助任务是输出单个字符。至于要从字符串中去掉字符,则有几种可能的选择。两种直观选择如下:

去掉最后一个字符

去掉第一个字符

首先来看第一个选择,也就是去掉最后一个字符的情况,如图2-6所示。
 

要使该解决方案有效,必须先输出字符串中的最后一个字符。因此在逆置字符串的其余部分之前必须输出最后一个字符。对于给定的字符串s,高层递归解决方案如下:
 

  1. writeBackward(s: string)  
  2. if (the string is empty)  
  3. Do nothing —this is the base case  
  4. else  
  5. {  
  6. Write the last character of s  
  7. writeBackward(s minus its last character)  
  8. }  

注释:writeBackward将字符串逆置

提示:递归解决方案必然涉及一个或者多个较小的问题,这些问题比原始问题更加靠近基例。必须保证这些较小的问题最终能够到达基例,如果无法保证会导致无法终止的算法。

这是该问题的概念化解决方案。要获得C++函数,必须解决一些实现问题。假定函数要接收一个参数:要逆置的字符串s。所有字符(包括空格)都是这个字符串的一部分。C++函数writeBackward如下所示:
 

  1. /** Writes a character string backward.  
  2. @pre  The string s to write backward.  
  3. @post  None.  
  4. @param s  The string to write backward. */  
  5. void writeBackward(string s)  
  6. {  
  7. int length = s.size(); // Length of string  
  8. if (length > 0)  
  9. {  
  10. // Write the last character  
  11. cout << s.substr(length-1, 1);  
  12. // Write the rest of the string backward  
  13. writeBackward(s.substr(0, length – 1)); // Point A  
  14. } // end if  
  15. // length == 0 is the base case - do nothing  
  16. } // end writeBackward  

注意,对writeBackward的递归调用使用了字符串s逐步变短的版本,以确保可到达基例。由于这个函数到达基例后什么都不做,因此并没有显式地处理基例。基例是隐式处理的。

可通过箱式跟踪来跟踪writeBackward的执行。与函数fact一样,各个箱包含递归调用的局部环境,本例中为输入参数s和局部变量length。此处的跟踪与图2-5所示的fact跟踪有些不同,因为作为void函数,writeBackward没有使用return语句返回计算结果。图2-7跟踪了使用字符串"cat"对writeBackward函数的调用。
 

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇2.2.2 箱式跟踪 下一篇2.3 执行动作的递归(2)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·HTTPS 详解一:附带 (2025-12-26 02:20:37)
·TCP/IP协议到底在讲 (2025-12-26 02:20:34)
·TCP和UDP在socket编 (2025-12-26 02:20:32)
·有没有适合新手练习 (2025-12-26 01:48:47)
·用清华镜像网怎么下 (2025-12-26 01:48:44)