(转)递归转非递归的思路和例子

转自:http://blog.51cto.com/cnn237111/1241956

某些算法逻辑,用递归很好表述,程序也很好写。理论上所有的递归都是可以转换成非递归的。如果有些场合要求不得使用递归,那就只好改成非递归了。

通常改成非递归算法的思路,就是使用临时的一个栈来存放计算的临时值。

下面演示2个例子。

示例一:

假设有如下的递归函数

f(1)=3

f(2)=11

f(n)=4*f(n-1)-f(n-2)

那么写成代码,这个递归函数就是如下:

1
2
3
4
5
6
7
8
9
static int f(int x)
        {
            if (x == 1)
                return 3;
            else if (x == 2)
                return 11;
            else
                return 4 * f(x - 1) - f(x - 2);
        }

如果改写成非递归,那么肯定是要用到循环。

由于计算第n个值的时候,要用到第n-1和第n-2个值,因此,至少要把这2个值存起来。然后使用的时候这2个值都出栈,计算出第n个值,然后,再把第n-1个值和第n个值入栈,以方便计算第n+1的值。具体代码如下:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static int f_1(int x)
        {
            Stack<int> s = new Stack<int>();
            for (int i = 1; i <= x; i++)
            {
                if (i == 1)
                    s.Push(3);
                else if (i == 2)
                    s.Push(11);
                else
                {
                    int tmp1 = s.Pop();//栈中至少有2个元素了,出栈后以计算下一个元素
                    int tmp2 = s.Pop();
                    int tmp = 4 * tmp1 - tmp2;
                    s.Push(tmp1);
                    s.Push(tmp);//计算结果入栈
                }
            }
            return s.Pop();//返回栈顶元素
        }

示例二:遍历二叉树

二叉树的先序遍历,中序遍历,后序遍历,通常是递归实现的,因为很好理解。此处不再赘述递归版本。

假设有一个二叉树:

image_thumb

先用代码构造出这棵树。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#region 节点的定义
class node
{
    public string nodevalue;
    public node leftchild, rightchild;
    public node()
    { }
    public node(string value)
    {
        nodevalue = value;
    }
    public void assignchild(node left, node right)//设定左右孩子
    {
        this.leftchild = left;
        this.rightchild = right;
    }
    public bool hasleftchild//是否有左孩子
    {
        get
        {
            return (leftchild != null);
        }
    }
    public bool hasrightchild//是否有右孩子
    {
        get
        {
            return (rightchild != null);
        }
    }
    public override string ToString()
    {
        return nodevalue;
    }
}
#endregion

***************************

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static void Main(string[] args)
      {
          node node_a = new node("a");
          node node_b = new node("b");
          node node_c = new node("c");
          node node_d = new node("d");
          node node_e = new node("e");
          node node_f = new node("f");
          node node_g = new node("g");
          node node_h = new node("h");
          node node_i = new node("i");
          //构造一棵二叉树
          node_a.assignchild(node_b, node_c);
          node_b.assignchild(node_d, node_e);
          node_c.assignchild(node_f, node_g);
          node_e.assignchild(node_h, node_i);
  }

****************************************

非递归版本实现先序遍历。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//先序遍历
 static void preorder_visit_1(node root)
        {
            Stack<node> s = new Stack<node>();
            s.Push(root);//先序遍历。首先访问的是根结点,把根节点放入栈中
            while (s.Count > 0)
            {
                node r = s.Pop();//当前要访问的结点出栈。
                Console.Write(r.nodevalue);
                //先序遍历的顺序是根,左,右。
                //由于栈的先入后出的特性,因此先插入右孩子,后插入左孩子,能保证取出来的时候是先左后右
                if (r.hasrightchild) //如果有右孩子,则右孩子入栈
                {
                    s.Push(r.rightchild);
                }
                if (r.hasleftchild)//如果有左孩子,则左孩子入栈
                {
                    s.Push(r.leftchild);
                }
            }
        }
//中序遍历
 static void inorder_visit_1(node root)
        {
            Stack<node> s = new Stack<node>();
            s.Push(root);
            while (s.Count > 0)
            {
                while (s.Peek() != null && s.Peek().hasleftchild)//把该节点的左子树全部遍历。
                    //如果s.Peek()==null,说明栈中null下的元素的左孩子已经遍历过了,该访问null下的元素本身了。
                {
                    s.Push(s.Peek().leftchild);
                }
                if (s.Peek() == null)
                    s.Pop();
                if (s.Count > 0)
                {
                    var node = s.Pop();
                    Console.Write(node.nodevalue);
                    s.Push(node.rightchild);//如果没有右子树,放入空结点
                }
            }
        }

转载于:https://www.cnblogs.com/heluan/p/8551615.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/571110.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux自动亮度,ubuntu亮度无法自动调节终极解决方案

关于ubuntu亮度无法自动调节的问题&#xff0c;纠结了我快两年&#xff0c;主要是自己懒&#xff0c;写了个脚本来调节亮度&#xff0c;不过还是稍显不便。近日兴起折腾了一番&#xff0c;终于找到问题根结了。There are many ways to control brightness. According to this d…

NHibernate:no persister for 异常

几种原因&#xff1a; 1、配置文件后缀名写错 mapping file 必须是.hbm.xml结尾 2、Web.config配置里面引用实体 <session-factory> ........................ <mapping assembly"Project.DomainModel"/> <!-- Here --> </session-factory>…

拦截器的的调用顺序

拦截器的的调用顺序 a&#xff1a;首先&#xff0c;要找到它自己有没有声明拦截器的引用&#xff0c;即<action>元素有没有<interceptor-ref>子元素&#xff0c;如果有&#xff0c;则不用继续寻找&#xff08;即不会再使用b,c即默认的拦截器栈等&#xff09;&#…

嵌入式linux 试卷,嵌入式Linux模拟试卷

B. 在目标机上开发&#xff0c;在宿主机上运行C. 在宿主机上开发&#xff0c;在宿主机上运行D. 在目标机上开发&#xff0c;在目标机上运行10. ARM9寄存器组有______个寄存器。【2.0分】A. 7B. 32C. 6D. 3711. 以下叙述中&#xff0c;不符合RICS特征的是______。【2.0分】A. 指…

iOS - 富文本

iOS--NSAttributedString超全属性详解及应用&#xff08;富文本、图文混排&#xff09; ios项目中经常需要显示一些带有特殊样式的文本&#xff0c;比如说带有下划线、删除线、斜体、空心字体、背景色、阴影以及图文混排&#xff08;一种文字中夹杂图片的显示效果&#xff09;。…

运维工程师必会的linux命令下载,运维工程师必会的109个Linux命令.pdf

Linux公社运维工程师必会的109 个Linux 命令版本 1.0崔存新目录1 文件管理 51.1 basename 51.2 cat 51.3 cd 61.4 chgrp 61.5 chmod 71.6 chown 81.7 comm 91.8 cp91.9 cut 101.10 dd 111.11 diff 121.12 dir 131.13 dos2unix 151.14 egrep 161.15 fgrep 161.16 file 161.17 fi…

pdf.js 文字丢失问题 .cmaps

使用pdf.js 展示pdf文件 需求&#xff1a;电子发票类的pdf文件&#xff0c;以base64流的形式请求到&#xff0c;在浏览器中展示pdf文件 遇到的问题&#xff1a; 正常展示后&#xff0c;部分文字无法正常显示&#xff0c; 正常显示如下&#xff1a; 文件目录&#xff1a; js:fun…

linux红黑树节点没有数据,真正理解红黑树,真正的(Linux内核里大量用到的数据 -电脑资料...

作为一种数据结构&#xff0c;红黑树可谓不算朴素&#xff0c;因为各种宣传让它过于神秘&#xff0c;网上搜罗了一大堆的关于红黑树的文章&#xff0c;不外乎千篇一律&#xff0c;介绍概念&#xff0c;分析性能&#xff0c;贴上代码&#xff0c;然后给上罪恶的一句话&#xff0…

bzoj3631: [JLOI2014]松鼠的新家

容易发现是树剖裸题。 然后毒瘤选手AKC表示好像可以用树上差分LCA做。 就这样。水题。 诶那你咋没秒切。 妈也看错样例&#xff0c;然后画错图&#xff0c;接着就是理解错题目&#xff0c;最后R成傻逼之时发现我ST表开数组的顺序错了。。。 废物。 #include<cstdio> #inc…

超过4g的文件怎么上传到linux,怎么免费上传大于4G的文件到百度云 大于4G的文件不开会员怎么上传到百度云...

4G管家appv1.0 安卓版类型&#xff1a;系统工具大小&#xff1a;13.1M语言&#xff1a;中文 评分&#xff1a;10.0标签&#xff1a;立即下载百度云可以非常方便大家存储一些大文件资料&#xff0c;而且百度云的容量也非常高&#xff0c;不过如果你是普通用户的话要想上传大于4g…

scanf和printf在c语言中的作用,C语言中的scanf与printf

最初学习C语言程序设计时&#xff0c;经常需要通过键盘交互方式请用户输入内容&#xff0c;并需要将用户计算的结果在屏幕上输出。为实现这样的操作&#xff0c;C语言提供了scanf与printf两个函数&#xff0c;使用它们之前&#xff0c;一般需要包含stdio.h头文件。语法是&#…

linux sed 循环多行,linux sed 多行处理详细总结

在正常情况下&#xff0c;sed将待处理的行读入模式空间&#xff0c;脚本中的命令就一条接着一条的对该行进行处理&#xff0c;直到脚本执行完毕&#xff0c;然后该行被输出&#xff0c;模式空间请空&#xff1b;然后重复刚才的动作&#xff0c;文件中的新的一行被读入&#xff…

c语言第六次上机作业,C语言第五次上机作业参考答案

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼#include#define N 3void average(int x[N][10]);void findgood(int x[N][10]);void findfail(int x[N][10]);void main(){//0:学号,1-5:成绩,6:平均分,7:第一门平均分,8:是否及格,9:是否优秀int stu[N][10]{0},i,j,s[N]{0};printf…

华农c语言实验1007答案,华农C语言题目及答案(完整版).docx

[题目6567&#xff1a;The first C Program]将下列程序输入visual c&#xff0c;编译、连接和运行该程序。#include"stdio.h"main(){printf("The first C Program\n");}答案#include #include int main(){printf("The first C Program\n");retur…

C语言中声明复数用什么字母,用c语言定义复数-20210407134457.docx-原创力文档

标准化管理处编码[BBX968T-XBB8968-NNJ668-MM9N]标准化管理处编码[BBX968T-XBB8968-NNJ668-MM9N]用c语言定义复数实验0 预备实验实验题目&#xff1a;用c语言的结构类型定义表示复数(1)用浮点型(2)实行-*、/运算实验代码&#xff1a;#include<>typedef struct{int e1,e2;…

go语言 c# 混合编程 pdf,C# 结合 Golang 开发

1. 实现方式与语法形式基本方式&#xff1a;将 Go 程序编译成 DLL 供 C# 调用。1.1 Go代码注意&#xff1a;代码中 export 的注释是定义的入口描述不能省略package mainimport "C"import "fmt"func main() {fmt.Println(Test())}var _count 0//Test ://ex…

android 屏幕坐标色彩,Android自定义View实现颜色选取器

Android 自定义View 颜色选取器&#xff0c;可以实现水平、竖直选择颜色类似 SeekBar 的方式通过滑动选择颜色。效果图xml 属性1.indicatorColor 指示点颜色2.indicatorEnable 是否使用指示点3.orientation 方向horizontal 水平vertical 竖直使用复制 \library\src…\ColorPick…

android移除动画,android – 如何使用ObjectAnimator删除动画的慢端?

我有这个ObjectAnimator&#xff1a;cloudAnim2 ObjectAnimator.ofFloat(cloud2ImageView,"x",500,1000);cloudAnim2.setDuration(3000);cloudAnim2.setRepeatCount(ValueAnimator.INFINITE);cloudAnim2.setRepeatMode(ValueAnimator.RESTART);cloudAnim2.start();c…

linux右键菜单的截图,Linux: 给右键菜单加一个“转换图片为jpg格式”

Linux上通常都会安装imagemagick这个小巧但又异常强大的工具。这个软件提供了一系列很好用的功能。这里说一说如何使用它的convert命令转换图片为jpg格式&#xff0c;以及如何把它添加到Thunar的右键菜单。convert转换图片为jpg格式用起来超简单&#xff1a;convert -format jp…

eclipse实现Android登录功能,eclipse开发安卓登录

划线的地方怎么解决啊&#xff1f;有没有大佬知道如何修改package com.example.login;import android.app.Activity;import android.content.Context;import android.content.Intent;import android.content.SharedPreferences;import android.content.SharedPreferences.Edito…