IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 算法设计与分析——递归 -> 正文阅读

[数据结构与算法]算法设计与分析——递归

何为递归

递归定义

在定义一个过程或函数时出现调用本过程或本函数的成分,称之为递归。
若调用自身,称之为直接递归。若过程或函数p调用过程或函数q,而q又调用p,称之为间接递归
任何间接递归都可以等价地转换为直接递归。
如果一个递归过程或递归函数中递归调用语句是最后一条执行语句,则称这种递归调用为尾递归
一般来说,能够用递归解决的问题应该满足以下三个条件:
1)需要解决的问题可以转化为一个或多个子问题来求解,而这些子问题的求解方法与原问题完全相同,只是在数量规模上不同。
2)递归调用的次数必须是有限的。
3)必须有结束递归的条件来终止递归。

何时使用递归

1)定义是递归的
许多数学公式、数列等的定义是递归的。例如,求n!和Fibonacci数列等。
2)数据结构是递归的
有些数据结构是递归的。例如单链表就是一种递归数据结构。
3)问题的求解方法是递归的
有些问题的解法是递归的,典型的有Hanoi问题求解。

递归模型

递归模型是递归算法的抽象,它反映一个递归问题的递归结构。例如:

fun(1)=1                    (1)   
fun(n)=n*fun(n-1)     n>1   (2) 

其中,第一个式子给出了递归的终止条件,第二个式子给出了fun(n)的值与fun(n-1)的值之间的关系,我们把第一个式子称为递归出口,把第二个式子称为递归体

递归算法的执行过程

  • 一个正确的递归程序虽然每次调用的是相同的子程序,但它的参量、输入数据等均有变化。
  • 在正常的情况下,随着调用的不断深入,必定会出现调用到某一层的函数时,不再执行递归调用而终止函数的执行,遇到递归出口便是这种情况。
  • 递归调用是函数嵌套调用的一种特殊情况,即它是调用自身代码。也可以把每一次递归调用理解成调用自身代码的一个复制件。
  • 由于每次调用时,它的参量和局部变量均不相同,因而也就保证了各个复制件执行时的独立性。
  • 系统为每一次调用开辟一组存储单元,用来存放本次调用的返回地址以及被中断的函数的参量值。
  • 这些单元以系统栈的形式存放,每调用一次进栈一次,当返回时执行出栈操作,把当前栈顶保留的值送回相应的参量中进行恢复,并按栈顶中的返回地址,从断点继续执行。

归纳起来,递归调用的实现是分两步进行的,第一步是分解过程,即用递归体将“大问题”分解成“小问题”,直到递归出口为止,然后进行第二步的求值过程,即已知“小问题”,计算“大问题”。

递归算法设计

递归算法设计的一般步骤

递归算法设计先要给出递归模型,再转换成对应的C/C++语言函数。
获取递归模型的步骤如下:
1)对原问题f(sn)进行分析,抽象出合理的“小问题”f(sn-1)
2)假设f(sn-1)是可解的,在此基础上确定f(sn)的解,即给出f(sn)与f(sn-1)之间的关系
3)确定一个特定情况(如f(1)或f(0))的解,由此作为递归出口

递归数据结构及其递归算法设计

递归数据结构的定义

采用递归方式定义的数据结构称为递归数据结构。在递归数据结构定义中包含的递归运算称为基本递归运算

基于递归数据结构的递归算法设计

1)单链表的递归算法设计
在设计不带头结点的单链表的递归算法时:
设求解以L为首结点指针的整个单链表的某功能为“大问题”。
而求解除首结点外余下结点构成的单链表(由L->next标识,而该运算为递归运算)的相同功能为“小问题”。
由大小问题之间的解关系得到递归体。
再考虑特殊情况,通常是单链表为空或者只有一个结点时,这时很容易求解,从而得到递归出口。
2)二叉树的递归算法设计
二叉树是一种典型的递归数据结构,当一棵二叉树采用二叉链b存储时:
设求解以b为根结点的整个二叉树的某功能为“大问题”。
求解其左、右子树的相同功能为“小问题”。
由大小问题之间的解关系得到递归体。
再考虑特殊情况,通常是二叉树为空或者只有一个结点时,这时很容易求解,从而得到递归出口。

基于归纳思想的递归算法设计

基于归纳思想的递归算法设计通常不像基于递归数据结构的递归算法设计那样直观,需要通过对求解问题的深入分析,提炼出求解过程中的相似性而不是数据结构的相似性,这就增加了算法设计的难度。
但现实世界中的许多问题的求解都隐含这种相似性,并体现计算思维的特性。

递归算法设计示例

例1:将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
请添加图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    struct ListNode* l3 = (struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode* p = l3;
    if(l1==NULL&&l2==NULL){
        l3->next=NULL;
    }
    while(l1!=NULL&&l2!=NULL){
        if(l1->val < l2->val){
            p->next=l1;
            p=l1;
            l1=l1->next;
        }else{
            p->next=l2;
            p=l2;
            l2=l2->next;
        }
    }
    if(l1!=NULL){
        p->next=l1;
    }
    if(l2!=NULL){
        p->next=l2;
    }
    return l3->next;
}

例2:给你一个单链表的头节点 head,请你判断该链表是否为回文链表。如果是,返回 true;否则,返回false。
请添加图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool isPalindrome(struct ListNode* head){
    int l=0;
    int a[100000];
    while(head!=NULL){
        a[l]=head->val;
        l++;
        head=head->next;
    }
    bool huiwen = true;
    for(int i=l/2-1;i>=0;i--){
        if(a[i]!=a[l-i-1]){
            huiwen=false;
        }
    }
    return huiwen;
}

例3:n皇后问题
问题描述】在n×n的方格棋盘上,放置n个皇后,要求每个皇后不同行、不同列、不同左右对角线。如下图所示是6皇后问题的一个解。
在这里插入图片描述
q[1…6]={2,4,6,1,3,5}
问题求解
请添加图片描述
对于(i,j)位置上的皇后,是否与已放好的皇后(k,q[k])(1≤k≤i-1)有冲突呢?

  • 显然它们不同列,若同列则有:q[k]==j;
  • 对角线有两条,若它们在任一条对角线上,则构成一个等边直角三角形,即|q[k]-j|==|i-k|。
(q[k]==j) || (abs(q[k]-j)==abs(i-k))

设queen(i,n)是在1~i-1列上已经放好了i-1个皇后,用于在i~n行放置n-i+1个皇后,则queen(i+1,n)表示在1~i行上已经放好了i个皇后,用于在i+1~n行放置n-i个皇后。
queen(i+1,n)比queen(i,n)少放置一个皇后。所以queen(i+1,n)是“小问题”,queen(i,n)是“大问题”。

queen(i,n) ≡ n个皇后放置完毕,输出一个解 若i>n
queen(i,n) ≡ 在第i行的合适的位置(i,j) 其他情况
在其上放置一个皇后;
queen(i+1,n);

bool place(int i,int j)		//测试(i,j)位置能否摆放皇后
{   if (i==1) return true;		//第一个皇后总是可以放置
    int k=1;
    while (k<i)			//k=1~i-1是已放置了皇后的行
    {	if ((q[k]==j) || (abs(q[k]-j)==abs(i-k)))
	    return false;
	k++;
    }
    return true;
}
void queen(int i,int n)		//放置1~i的皇后
{   if (i>n) 
	dispasolution(n);		//所有皇后放置结束
    else
    {	for (int j=1;j<=n;j++)	//在第i行上试探每一个列j
	    if (place(i,j))		//在第i行上找到一个合适位置(i,j)
	    {	q[i]=j;
		queen(i+1,n);
	    }
    }
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-19 12:08:35  更:2021-10-19 12:10:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/24 11:55:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码