数据结构教程读书笔记_递归

递归的定义

在定义一个过程或函数时,出现直接或者间接调用自己的成分,称之为递归。 

若直接调用自己,称之为直接递归;若间接调用自己,称之为间接递归

如果一个递归函数中递归调用语句是最后一条执行语句,则称这种递归调用为尾递归。 

尾递归算法:可以用循环语句转换为等价的非递归算法

其他递归算法:可以通过栈来转换为等价的非递归算法

使用递归的场景

(1)定义是递归的

有许多数学公式、数列等的定义是递归的。例如,求n!Fibonacci数列等。这些问题的求解过程可以将其递归定义直接转化为对应的递归算法。

(2)数据结构是递归的

有些数据结构是递归的。 例如, 单链表就是一种递归数据结构, 其节点类型定义如下:

1 typedef struct LNode
2 { 
3     ElemType data;
4     struct LNode *next; //指向同类型节点的指针
5 } LinkList;

不带头节点单链表示意图:

(3)问题的求解方法是递归的

递归模型

一个递归模型是由递归出口递归体两部分组成。

递归出口确定递归到何时结束;递归体确定递归求解时的递推关系。

f(sn) = g(f(si)f(si+1)f(sn-1)cjcj+1cm)

其中g是一个非递归函数,c是常量。

把一个不能或不好直接求解的“大问题”转化成一个或几个“小问题”来解决; 再把这些“小问题”进一步分解成更小的“小问题” 来解决。 直到每个“小问题”都可以直接解决(此时分解到递归出口)。 
但递归分解不是随意的分解,递归分解要保证“大问题”与“小问题”相似,即求解过程与环境都相似。

f(s1) = m1
f(sn) = g(f(sn-1)cn-1)

f(sn)分解过程如下:

 

遇到递归出口发生“质变” , 即原递归问题便转化成可以直接求解的问题。 求值过程:

这样f(sn)便计算出来了,因此递归的执行过程由分解求值两部分构成。

求递归模型的步骤

1)对原问题f(s)进行分析, 称为“ 大问题” ,假设出合理的“ 小问题” f(s’)

2)假设f(s’)是可解的, 在此基础上确定f(s)的解, 即给出f(s)f(s’)之间的关系,即递归体

3)确定一个特定情况(如f(1)f(0))的解,即递归出口

应用

1、采用递归算法求实数数组A[0..n-1]中的最小值

分析:

假设f(A,i-1)已求出, 则f(A,i)=MIN(f(A,i-1)A[i]), 其中MIN()为求两个值较小值函数。

i=0时,只有一个元素,有f(A,i)=A[0]

递归模型:
f(A,i) = A[0] i=0
f(A,i) = MIN(f(A,i-1)A[i]) 其他情况

代码:

 1 float f(float A[], int i)
 2 { 
 3     float m;
 4     if (i == 0)
 5         return A[0];
 6     else
 7     { 
 8         m = f(A, i - 1);
 9         
10         if (m > A[i])
11             return A[i];
12         else
13             return m;
14     }
15 }

2、求单链表中数据节点个数

分析:

空单链表的数据节点个数为0,即 f(L)=0 L=NULL

对于非空单链表:

考虑一下我们的链表模型:

则可以得出下面的图: 

递归模型: 

f(L) = 0 L=NULL
f(L) = f(L->next) + 1 其他情况

代码:

1 int count(Node *L)
2 { 
3     if (L == NULL)
4         return 0;
5     else
6         return count(L->next) + 1;
7 }

3、正向显示所有节点值

分析:

假设f(L->next)已求解
f(L)等价于输出L->dataf(L->next);

递归模型: 

f(L) 不做任何事件 当L=NULL
f(L) 输出L->data;f(L->next) 其他情况

代码:

1 void traverse(Node *L)
2 { 
3     if (L == NULL) 
4         return;
5         
6     printf("%d ", L->data);
7     traverse(L->next);
8 }

4、反向显示所有节点值 

分析:

假设f(L->next)已求解
f(L)等价于f(L->next);输出L->data

递归模型: 

f(L) 不做任何事件 当L=NULL
f(L) f(L->next);输出L->data 其他情况

代码:

1 void traverseR(Node *L)
2 { 
3     if (L == NULL) 
4         return;
5 
6     traverseR(L->next);
7     printf("%d ", L->data);
8 }

5、采用递归算法求解迷宫问题,并输出从入口到出口的所有迷宫路径

分析:

递归模型:

mgpath(xi,yi,xe,ye,path) 将(xi,yi)添加到path中;输出path中的迷宫路径;     若(xi,yi)=(xe,ye)
mgpath(xi,yi,xe,ye,path) 对于(xi,yi)四周的每一个相邻方块(i,j):
              (1)将(xi,yi)添加到path中;
              (2)置mg[xi][yi]=-1;
              (3)mgpath(i,j,xe,ye,path);
              (4)path回退一步并置mg[xi][yi]=0; (在一个“小问题” 执行完后回退是为了找所有解
                                若(xi,yi)不为出口且可走

代码:

 1 typedef struct
 2 { 
 3     int i; //当前方块的行号
 4     int j; //当前方块的列号
 5 } Box;
 6 
 7 typedef struct
 8 { 
 9     Box data[MaxSize];
10     int length; //路径长度
11 } PathType; //定义路径类型
12 
13 int mg[M+2][N+2] = //M=4, N=4
14 { 
15     {1, 1, 1, 1, 1, 1},
16     {1, 0, 0, 0, 1, 1},
17     {1, 0, 1, 0, 0, 1},
18     {1, 0, 0, 0, 1 ,1},
19     {1, 1, 0, 0, 0, 1},
20     {1, 1, 1, 1, 1, 1} 
21 };
22 
23 void mgpath(int xi,int yi,int xe,int ye,PathType path)
24 //求解路径为:(xi,yi)  (xe,ye)
25 { 
26     int di,k,i,j;
27     if (xi == xe && yi == ye)
28     { 
29         path.data[path.length].i = xi;
30         path.data[path.length].j = yi;
31         path.length++;
32         printf("迷宫路径%d如下:
",++count);
33 
34         for (k = 0; k < path.length; k++)
35         { 
36             printf("	(%d, %d)", path.data[k].i, path.data[k].j);
37             
38             if ((k + 1) % 5 == 0) //每输出每5个方块后换一行
39                 printf("
");
40         }
41         printf("
");
42     }
43     else //(xi,yi)不是出口
44     { 
45         if (mg[xi][yi] == 0) //(xi,yi)是一个可走方块
46         { 
47             di= 0;
48             while (di<4) //对于(xi,yi)四周的每一个相邻方位di
49             { 
50                 switch(di) //找方位di对应的方块(i,j)
51                 {
52                     case 0: 
53                         i = xi-1; j = yi; break;
54                     case 1: 
55                         i = xi; j = yi + 1; break;
56                     case 2:
57                         i = xi + 1; j = yi; break;
58                     case 3:
59                         i = xi; j = yi - 1; break;
60                 } 
61                 path.data[path.length].i = xi;
62                 path.data[path.length].j = yi;
63                 path.length++; //路径长度增1
64                 mg[xi][yi]=-1; //避免来回重复找路径
65 
66                 mgpath(i,j,xe,ye,path);
67 
68 path.length--; //回退一个方块 69 mg[xi][yi]=0; //恢复(xi,yi)为可走 70 di++; 71 } //-while 72 } //- if (mg[xi][yi]==0) 73 } //-递归体 74 } 75 76 int main() 77 { 78 PathType path; 79 path.length=0; 80 81 mgpath(1, 1, 4, 4, path); 82 83 return 0; 84 }

初始:

结果:

   

本文图片参考自:配套ppt课件

原文地址:https://www.cnblogs.com/abc-begin/p/7709185.html