算法与程序设计之递归程序设计

递归程序设计

1、递归的定义

递归是指在函数定义中有吊影函数自身的方法,若函数p函数定义中又调用了函数p,这种递归称为直接递归,若p函数调用函数q, 函数q 有调用了 函数p,称之为间接递归。
一般来说,能够用递归解决的问题应该满足三个条件
1、需要解决的问题可以转换为一个或多个子问题来求解,二这些子问题的求解方法与原问题完全相同,只是数量规模上的不同。
2、递归的次数必须是有限的。
3、必须有结束递归的天界来终止递归

2、何时使用递归

1、定义是递归的
有许多数学公式,数列和概念的定义是递归的,如 n! 、斐波那契数列
2、数据结构是递归的
比如单链表 二叉树

struct List
{
	int data;
	struct List *next;
};

struct Tree
{
	int data;
	struct Tree *left;
	struct Tree *right;
};

3、问题的求解方案是递归的
有些问题的求解方法是递归的,比如 汉诺塔问题。

3、递归的模型

在解决递归问题的时候,先建立一个递归的模型,如:

f(n) = 1  当(n = 1)时
f(n) = nf(n-1) 当(n > 1)时

4、递归算法的执行过程

在这里先不考虑求解问题的效率,比如斐波那契数列
算法与程序设计之递归程序设计
如上图,在求f(5)的时候,先求f(4) 和 f(3)
要求f (4) 先求f(3) 和 f(2)
要求f(3) 先求 f(2) 和 f(1)
f(2) 和 f(1) 已知,再往上求 f(3) f(4) f(5)
先向下递归,再向上求解,在递归的过程中,调用函数自身,函数的调用会有系统栈帧的开辟。

从上可以得出:
1、递归的执行是通过系统栈来实现的。
2、每次递归就需要将参数,局部变量和返回地址作为一个栈元素入栈一次,入栈的次数越多,递归的深度越深。
3、每遇到递归的出口,就会出栈一次,直到栈中的元素为空为止。

递归设计解题过程

n皇后问题,如果不了解n皇后,可自行查询一下具体的细节,这里不多做说明。

#include <stdio.h>
#include <math.h>

#define MAX 20
//p[i]表示 第i个皇后的位置
int p[MAX];

//打印函数
void Display(int n)
{
    int i = 1;
    for(; i <= n; i++)
    {
        printf("%d ",p[i]);
    }
    printf("\n");
}

//判断j位置是否满足要求
int Place(int i,int j)
{
    int k = 1;
    for(k = 1; k < i; k++)
    {
        if(p[k] == j || abs(p[k]-j) == abs(i-k))
        {
            return 0;
        }
    }
    return 1;
}

void Queen(int i,int n)
{
	//i表示当前需要安排第几个皇后,
	//如果最后一个已经放到了相应的位置,则直接输出,递归出来
    if(i > n)
    {
        Display(n);
    }
    int j = 1;
    //从 1 开始 遍历 找到合法的位置
    for(; j <= n; j++)
    {
        if(Place(i,j) == 1)
        {
            p[i] = j;
            //找到一个合法的位置,递归开始找下一个皇后的位置
            Queen(i+1,n);
        }
    }
}


int main()
{
    Queen(1,4);
    return 0;
}

结语

这里先将递归的基本概念以及求解方法介绍一下,对问题的求解篇幅不大,以后继续更新递归求解问题的方法。