[原创] 算法之递归(1)

算法之递归(1)

最近事情太多了,很少有时间可以完全静下来认真研究一些东西;每当专注的写代码的时候,总是被其他事情打断。还好,礼拜天来了,总算可以抽出一些时间了J

《代码之美》第一章有一个关于模式匹配的问题,即根据正则表达式在相应的文本中找到匹配的值,找到返回1,没找到返回0。撇开具体的实现,里面优美的递归调用倒是深深地吸引了我。于是,我开始重新思考递归,毕竟有些细节之前的思考还不够到位。

什么是递归

我的印象中的递归是函数调用自身来完成预先定义的操作。当然,实际涉及的内容更多,比如退出递归的条件,代码逻辑,参数等等。

可以将递归理解为栈,即调用序列是以顺序结构的形式并遵循后进先出的顺序存放在栈中的。举个例子来说,加入存在这样的调用A()->B()->C()->D(),那么其在栈中的顺序如下,


A() : int


B() : int


C() : int


D() : int

通过这个例子不难看出,将B,C,D的名字全部换成A,就是递归调用A的全部过程。

我们来看一个具体的例子,如何计算1到N个自然整数的和。

{1, 2, 3, 5, …, n}

解法一

定义一个全局变量,用来做存储当前的和。

具体实现如下

        int sum = 0;

        private void GetSum(int n)

        {

            if (n == 0) return;

            if (n < 0)

                throw new ArgumentException("Invalid input.");

            sum += n;

            GetSum(n - 1);

        }

这个递归逻辑上没有问题,但是多定义了一个变量,作为最终的用户,需要在其上面再封装一层可以使用。当然,也可以在写一个函数重新封装,然后expose这个wrap后的版本。

那么有没有更好的解决方案?

解法二

定义一个有返回值的函数。

开篇的时候,我介绍递归类似于堆栈,所以递归调用也遵循后调用现出的原则。如果加上返回值,那么就只需要计算当前的n值于n之前所有值的和即,便可以得到n个数的和。比如有10个数,当前n是5,那么这层递归是5的和。

我们先来看一下代码,然后再做具体的分析。

        private int GetSumWithReturn(int n)

        {

            if (n < 0)

            {

                throw new ArgumentException("Invalid input.");

            }

            if (n == 0)

                return 0;

            return n + GetSumWithReturn(n - 1);

        }

分析解法二

  1. 当n小于0是,认为是一个非法操作。
  2. 当n等于0是,认为是已经计算到最小值,此时可以退出递归。
  3. 返回当前n的值与n-1之前

以n等于5为例,栈的结构如下,注意,从下自上看并且注意高亮的部分。(因为栈的顺序写反了,所要从下自上看,下面是栈顶)


Function Call


Function Body


GetSumWithReturn(5)


private int GetSumWithReturn(int n)   // n = 5

{

if (n < 0)

{

throw new ArgumentException("Invalid input.");

}

if (n == 0)

return 0;

return n + GetSumWithReturn(n - 1);// 5 + 10 = 15, return 15

}


GetSumWithReturn(4)


private int GetSumWithReturn(int n)   // n = 4

{

if (n < 0)

{

throw new ArgumentException("Invalid input.");

}

if (n == 0)

return 0;

return n + GetSumWithReturn(n - 1);// 4 + 6 = 10, return 10

}


GetSumWithReturn(3)


private int GetSumWithReturn(int n)   // n = 3

{

if (n < 0)

{

throw new ArgumentException("Invalid input.");

}

if (n == 0)

return 0;

return n + GetSumWithReturn(n - 1);// 3 + 3 = 6, return 6

}


GetSumWithReturn(2)


private int GetSumWithReturn(int n)   // n = 2

{

if (n < 0)

{

throw new ArgumentException("Invalid input.");

}

if (n == 0)

return 0;

return n + GetSumWithReturn(n - 1);// 2 + 1 = 3, return 3

}


GetSumWithReturn(1)


private int GetSumWithReturn(int n)   // n = 1

{

if (n < 0)

{

throw new ArgumentException("Invalid input.");

}

if (n == 0)

return 0;

return n + GetSumWithReturn(n - 1);// 1 + 0 = 1, return 1

}


GetSumWithReturn(0)


private int GetSumWithReturn(int n)   // n = 0

{

if (n < 0)

{

throw new ArgumentException("Invalid input.");

}

if (n == 0)       // n = 0, then return 0.

return 0;

return n + GetSumWithReturn(n - 1);

}

时间: 2024-10-09 12:24:24

[原创] 算法之递归(1)的相关文章

[原创] 算法之递归(3)- 链表操作

算法之递归(3)- 链表操作 递归(2)尝试了一个单链表的遍历,同时又分析了如何添加自己的操作,是在递归调用之前,还是在递归调用之后. 今天,打算将问题深入一下,即添加相应的操作在递归的过程中. (免责声明:下面的解法纯属娱乐 ,另外,示例代码未经编译和调试,许多想法未经实践验证.) 查找链表当中倒数第N个节点. 解法一 逐层递归,遍历到最后一个节点,并从返回的节点一次向后递归,遍历N次,找到倒数第N个节点. private LNode targetNode = null; private LN

[原创] 算法之递归(2)- 链表遍历

算法之递归(2)- 链表遍历 在递归(1)中,简单的介绍了递归的思想,并且通过一个例子简单阐述了递归是如何工作的,并且递归的实现是以线性结构来表示的.之所以用线性的,是因为其易于理解:如果使用树结构,将加大对问题的难度,不利于初学者理解递归的思想. 为什么用递归 关 于为什么用递归,我个人的理解是递归不要违背算法的初衷,即期待传入xxx值,加工后返回xxx值.不要为了递归而递归,容易造成对函数语义的奇异.另 外,通过递归,可以让代码更加整洁,短小,精湛,优美.当然,还会存在一定程度的性能损耗:不

[原创] 算法之递归(4)- 应用

最近带着几个在做一个项目,UI层面用的是WPF.之前很少深入的接触WPF,不过接触后,发现WPF的却是很强大. 至少在界面设计上的用户体验较WinForm有了大幅提升. 项目中需要通用化几个样式,并将样式赋值给相应的控件.控件是根据配置文件动态生成的,配置文件是xml格式的层次化较多的结构.所以在动态生成的过程中采用了递归的方式来实现. 下面是一个模拟实例. 目标: 将程序集“PresentationFramework"的所有类型添加到TreeView里面,如果一个类型存在基类行,那么先加入基类

java数据结构与算法之递归思维(让我们更通俗地理解递归)

[版权申明]转载请注明出处(请尊重原创,博主保留追究权) http://blog.csdn.net/javazejian/article/details/53452971 出自[zejian的博客] 关联文章: java数据结构与算法之顺序表与链表设计与实现分析 java数据结构与算法之双链表设计与实现 java数据结构与算法之改良顺序表与双链表类似ArrayList和LinkedList(带Iterator迭代器与fast-fail机制) java数据结构与算法之栈(Stack)设计与实现 j

Java数据结构和算法之递归

四.递归 递归是函数调用自身的一种特殊的编程技术,其应用主要在以下几个方面:   阶乘 在java当中的基本形式是: Public  void  mothed(int n){//当满足某条件时: Mothed(n‐1): } 递归二分查找 Java二分查找实现,欢迎大家提出交流意见.  /** *名称:BinarySearch *功能:实现了折半查找(二分查找)的递归和非递归算法. *说明: *     1.要求所查找的数组已有序,并且其中元素已实现Comparable<T>接口,如Integ

数据结构与算法5: 递归(Recursion)

数据结构与算法5: 递归(Recursion) 写在前面 <软件随想录:程序员部落酋长Joel谈软件>一书中<学校只教java的危险性>一章提到,大学计算机系专业课有两个传统的知识点,但许多人从来都没搞懂过,那就是指针和递归.我也很遗憾没能早点熟练掌握这两个知识点.本节一些关键知识点和部分例子,都整理自教材或者网络,参考资料列在末尾.如果错误请纠正我. 思考列表: 1)什么程序具有递归解决的潜质? 2)递归还是非递归算法,怎么选择? 3)递归程序构造的一般模式 1.递归定义 首要引

二分查找算法(递归与非递归两种方式)

首先说说二分查找法. 二分查找法是对一组有序的数字中进行查找,传递相应的数据,进行比较查找到与原数据相同的数据,查找到了返回1,失败返回对应的数组下标. 采用非递归方式完成二分查找法.java代码如下所示. /* * 非递归二分查找算法 * 参数:整型数组,需要比较的数. */ public static int binarySearch(Integer[]srcArray,int des){ //第一个位置. int low=0; //最高位置.数组长度-1,因为下标是从0开始的. int h

全排列算法的递归与非递归实现

全排列算法的递归与非递归实现 全排列算法是常见的算法,用于求一个序列的全排列,本文使用C语言分别用递归与非递归两种方法实现,可以接受元素各不相同的输入序列. 题目来自leetcode: Given a collection of numbers, return all possible permutations. For example, [1,2,3] have the following permutations: [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3

编程算法 - 背包问题(递归) 代码(C)

背包问题(递归) 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 有n个重量和价值分别为w,v的物品, 从这些物品中挑选出总重量不超过W的物品, 求所有挑选方案中价值总和的最大值. 即经典动态规划问题. 可以使用深度优先搜索, 把每个部分都遍历到, 选取最优解, 但不是最好的方法. 代码: /* * main.cpp * * Created on: 2014.7.17 * Author: spike */ /*eclipse cdt, gc