青岛大学_王卓老师【数据结构与算法】Week05_11_栈与递归_学习笔记

本文介绍了递归的概念,通过阶乘和Fibonacci数列举例说明递归应用,并探讨了递归在解决数学函数、数据结构和特定问题(如迷宫、Hanoi塔)中的角色。此外,文章讨论了分治法作为递归问题的解决方案,以及如何通过循环转换递归以提高效率,包括尾递归和单向递归的转换示例。
摘要由CSDN通过智能技术生成

本文是个人学习笔记,素材来自青岛大学王卓老师的教学视频。

一方面用于学习记录与分享,

另一方面是想让更多的人看到这么好的《数据结构与算法》的学习视频。

如有侵权,请留言作删文处理。

课程视频链接:

数据结构与算法基础–第05周11–3.4栈和递归

📚 【Week05】11_栈与递归

递归的定义

(1) 若一个对象部分地包含它自己,或用它自己给自己定义,则称这个对象是递归的。

(2) 若一个过程直接或间接地调用自己,则称这个过程是递归的过程。

例如:递归求 n 的阶乘

long Fact(long n){
	if(n == 0)
        return 1;
    else
        return (n * Fact(n-1));
}
以下三种情况尝尝用到递归方法
(1) 递归定义的数学函数

阶乘函数

在这里插入图片描述

2 阶 Fibonaci 数列

在这里插入图片描述

(2) 具有递归特性的数据结构

在这里插入图片描述

(3) 可递归求解的问题

迷宫问题

Hanoi 塔问题

递归问题——用分治法求解
分治法

对于一个较为复杂的问题,能够分解成几个相对简单的且解法相同或类似的子问题来求解

必备的三个条件

(1) 能够将一个问题转变为一个新问题,且新问题与原问题的解法相同或类同,不同的仅是处理的对象,且这些处理对象是变化且有规律的

(2) 可以通过上述转化而使问题简化

(3) 必须有一个明确的递归出口,或称递归的边界

分治法求解递归问题算法的一般形式
void p(参数表){
    if(递归结束条件)
        可直接求解步骤;	// -- 基本项
    else
        p(较小的参数);	 // -- 归纳项
}

例如

long Fact(long n){
	if(n == 0)
        return 1;					// -- 基本项
    else
        return (n * Fact(n-1));		// -- 归纳项
}
函数调用过程

调用前,系统完成:

(1) 将实参,返回地址等传递给被调用函数

(2) 为被调用函数的局部变量分配存储区

(3) 将控制转移到被调用函数的入口

调用后,系统完成:

(1) 保存被调用函数的计算结果

(2) 释放被调用函数的数据区

(3) 依照被调用函数保存的返回地址将控制转移到调用函数

当多个函数构成嵌套调用时:
int main(void){
    ...;
    y = fact(3);
    ...;       
}

double fact(int n){
    ...;
    z = mypow(3.5, 2);
    ...;
}

double mppow(double x, int n){
    ...;
}


遵循后调用的先返回

求解阶乘 n ! 的过程
long Fact(long n){
	if(n == 0)
        return 1;
    else
        return (n * Fact(n-1));
}

在这里插入图片描述

递归函数调用的实现

在这里插入图片描述

进行 fact(4) 调用的系统栈的变化状态

在这里插入图片描述

递归的优缺点

优点:结构清晰,程序易读

缺点:每次调用要生成工作记录,保存状态信息,入栈;返回时要出栈,恢复状态信息。时间开销大。

递归 -> 非递归

方法1:尾递归、单向递归 -> 循环结构

方法2:自用模拟系统的运行时栈

尾递归 -> 循环结构
long Fact(long n){
	if(n == 0)
        return 1;
    else
        return (n * Fact(n-1));
}

转换为循环

long Fact(long n){
	t = 1;
	for(int i=1; i<n; i++){
		t = t*i;
	}
    return t;
}
单向递归 -> 循环结构

虽然有一处以上的递归调用语句,但各次递归调用语句的参数只和主调函数有关,相互之间参数无关,

并且这些递归调用语句处于算法的最后

// Fibonacci 数列
long Fib(long n){
    if(n == 1 || n == 2)
        return 1;
    else 
        return (Fib(n-1) + Fib(n-2));
}

转换为

// Fibonacci 数列
long Fib(long n){
    if(n == 1 || n == 2)
        return 1;
    else {
        t1 = 1;
        t2 = 1;
        for(i=3; i<n; i++){
            t3 = t1 + t2;
            t1 = t2;
            t2 = t3;
        }
        
        return t3;
    }
}
借助栈改写递归

(1) 递归程序在执行时,需要系统提供栈来实现

(2) 仿照递归算法执行过程中递归工作栈的状态变化可写出相应的非递归程序

(3) 改写后的非递归算法与原来的递归算法相比,结构不够清晰,可读性较差,有的还需要经过一系列优化

了解内容

借助栈改写递归的方法

(1) 设置一个工作栈存放递归工作记录 (包括实参、返回地址及局部变量等)。

(2) 进入非递归调用入口 (即被调用程序开始处)将调用程序传来的实在参数和返回地址入栈(递归程序不可以作为主程序,因而可认为初始是被某个调用程序调用)。

(3) 进入递归调用入口: 当不满足递归结束条件时,逐层递归,将实参、返回地址及局部变量入栈,这一过程可用循环语句来实现一模拟递归分解的过程。

(4) 递归结束条件满足,将到达递归出口的给定常数作为当前的函数值。

(5) 返回处理: 在栈不空的情况下,反复退出栈顶记录,根据记录中的返回地址进行题意规定的操作,即逐层计算当前函数值,直至栈空为止一模拟递归求值过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值