递归与常见问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了递归与常见问题相关的知识,希望对你有一定的参考价值。

一、函数调用时的栈

函数调用时的栈
?程序中的“函数调用栈”是栈数据结构的一种应用
?函数调用栈一般是从高地址向低地址增长的
??栈底为内存的高地址处
??栈顶为内存的低地址处
?函数调用栈中存储的数据为活动记录
技术图片
程序中的栈
?在不断的压栈过程中造成栈空间耗尽而产生栈溢出
?栈溢出常由于函数递归过深或局部数组过大造成

二、递归的应用

?递归是一种数学上分而自治的思想
?递归将大型复杂问题转化为与原问题相同但规模较小的问题进行处理
?递归需要有边界条件
??当边界条件不满足时,递归继续进行
??当边界条件满足时,递归停止
斐波拉切数列
斐波纳契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)

int fibolac(int n)
{
    if((1 == n)||(2 == n))
    {
        return 1;   
    }
    else
    {
        return fibolac(n-1)+fibolac(n-2);
    }

}

字符串长度
求取字符串长度可使用递归的方式来求取

int string_len(const char* p)
{
    if(p == NULL)
    {
        return -1;
    }
    else if(*p == ‘‘)
    {
        return 0; 
    }
    else
    {
        return string_len(p+1) + 1; 
    }
}

全排列
假设集合是{a,b,c},那么这个集合中元素的全部排列是{(a,b,c),(a,c,b),(b,a,c),(b,c,a),(c,a,b),(c,b,a)},显然,给定n个元素共同拥有n!种不同的排列,假设给定集合是{a,b,c,d},能够用以下给出的简单算法产生其全部排列,即集合(a,b,c,d)的全部排列有以下的排列组成
?以a开头后面跟着(b,c,d)的排列
?以b开头后面跟着(a,c,d)的排列
?以c开头后面跟着(a,b,d)的排列
?以d开头后面跟着(a,b,c)的排列

int permutation(char s[],int b,int e)
{
    if((b>=0) && (b<=e))
    {
        if(b == e)
        {
            printf("%s
",s);
        }
        else
        {
            int i = 0;
            for(i = b; i<=e; i++)
            {
                if(isswap(s,b,i))           //去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换
                {
                    char c = s[b];          //交换位置
                    s[b] = s[i];
                    s[i] = c;
                    permutation(s,b+1,e);

                    c = s[b];              //交换位置
                    s[b] = s[i];
                    s[i] = c;
                }
            }
        }
    }
} 

汉诺塔问题
该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。
技术图片

/*
   n:需要移动的盘子数量
   a:起始位置
   b:需要借助的柱子 
   c:需要移动到的柱子 
*/
int hannoi(int n, char a, char b, char c)
{
    if(1 == n)
    {
        printf("%c-->%c
",a,c);
    }
    else
    {
        hannoi(n-1, a, c, b);
        printf("%c-->%c
",a,c);
        hannoi(n-1, b, a, c);
    }
    return 0;
} 

八皇后问题
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

#define N 8

typedef struct _tag_Pos
{
    int ios;
    int jos;
} Pos;                     //位置检查 

static char board[N+2][N+2];
static Pos pos[] = { {-1, -1}, {-1, 0}, {-1, 1} };     //偏移位置 
static int count = 0;                                  //符合要求的个数 

void display()
{
    int i = 0;
    int j = 1;

    for(i=0; i<N+2; i++)
    {
        for(j=0; j<N+2; j++)
        {
            printf("%c", board[i][j]);
        }

        printf("
");
    }
}

void init_queen()
{
    int i,j;
    for(i=0;i<N+2;i++)
    {
        board[0][i] = ‘#‘;
        board[i][0] = ‘#‘;
        board[N+1][i] = ‘#‘;
        board[i][N+1] = ‘#‘;    
    }

    display();
}

int check(int i,int j)
{
    int ret = 1;
    int p = 0;

    for(p=0; p<3; p++)
    {
        int ni = i;
        int nj = j;

        while( ret && (board[ni][nj] != ‘#‘) )
        {
            ni = ni + pos[p].ios;
            nj = nj + pos[p].jos;

            ret = ret && (board[ni][nj] != ‘*‘);
        }
    }
    return ret; 
}

int find(int i)                       //查找的第i行 
{
    int j;
    if(i > N)
    {
        count++;
        printf("Solution: %d
", count);
        display();                   //显示 
        getchar(); 
    }
    else
    {
        for(j=1;j<=N;j++)
        {
            if(check(i,j))
            {
                board[i][j] = ‘*‘;          
                find(i+1);
                board[i][j] = ‘ ‘;            //????
            }   
        }   
    } 
}

数字的分解问题

输出正整数和等于n的所有不增的正整数和式,如:
4=4
4=3+1
4=2+2
4=2+1+1
4=1+1+1+1

a:用于存放分解的数
n:需要分解的数的和
k:分解的深度 
int integer_fac(int a[],int n,int k)
{
    int j,p;
    for(j=n; j>=1; j--)
    {
        if(j <= a[k-1])
        {
            a[k] = j;
            if(j == n)
            {
                printf("%d = %d",a[0],a[1]);
                for(p=2;p<=k;p++)
                {
                    printf("+%d",a[p]);
                }
                printf("
");
            } 
            else
            {
                integer_fac(a,n-j, k+1);
            }   
        }
    }  
    return 0;
} 

以上是关于递归与常见问题的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript - 代码片段,Snippets,Gist

executePendingTransactions 的递归入口

精心收集的 48 个 JavaScript 代码片段,仅需 30 秒就可理解!(转载)

CSP核心代码片段记录

返回函数调用与仅在递归期间再次调用函数有啥区别?

nodejs常用代码片段