递归理解

 递归的过程:

递归理解

递归能够解决问题的两个要素:

  • 结束条件:  在递归到多少层之后结束递归
  • 接近条件: 每次递归,都更接近结束条件.
  • 附加条件: 子问题重叠问题,当递归算法中有重叠子问题,则效率往往极低,(指数时间复杂度).如求斐波那契数.

 

递归算法设计注意点:

  • 分支:每次递归产生几个子问题(当含多个子问题,往往每层递归都会带有循环)
    • 当产生多个分支时(事实大多数情况为多个分支),考虑该分支的结束条件和对哪条分支进行递归的递归条件.
    • 当产生单条分支时,分支结束条件即整个问题的结束条件,每次都对这条分支进行递归,但是需要计算出对子问题进行递归起始位置.如(字符串末尾匹配算法:my_strrchr(str+1, ch)):此处,需要计算合理的str.

 

  • 方向: 问题的解决是在递归过程中解决,还是满足递归限制条件后回收.
    • 第二种情况往往需要对递归结果进行回收.
    •  

递归算法实例分析:

 

 

字符匹配算法

问题描述: 找出字符串中最后一个与待匹配字符匹配的位置.

分析: 1.结束条件,字符串末尾  2.每次递归调用都接近字符串末尾

代码:

char *my_strrchr(char const *string, char ch)

{

  char const *str = string;

while(*str != '\0') //结束条件,字符串末尾

{

if(*str == ch)    //递归条件

 return my_strrchr(str+1, ch); //递归返回一次后,直接全部退出.

else 

{   

  str++;  //计算str,确定下一次递归调用的子问题.

}

}

return string;

}

 

 

八皇后问题

问题描述:

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

递归理解

解决思路:

  • 按行进行递归,按列进行循环.每当在i行找到满足条件的落子处后,递归到i+1行,利用循环,对该行每列进行判断,是否有满足条件的落子处,当能找到8行都满足条件的落子,则为选出了一种合法的落子方式.
  • 当在某一行遍历所有列都不满足落子条件时,已经不可能找出8行满足的落子方式,因此直接退出递归.回到上一层递归,使用循环,找出该行下一个满足条件的落子点.若依然没有合适的落子点,则再次返回上一层递归.

算法设计:

  • 方向: 在递归过程中解决问题
  • 分支:每次至多产生8个分支,至少产生0个分支.
    • 分支结束条件: 本层无满足合法落子位置
    • 分支递归条件: 本层存在合法落子位置

代码:

void eight_queen(int row, int n, int (*chess)[8])

{

 

/*1.赋值临时数组,因为每一次递归都有失败的风险,当失败的时候便舍弃掉临时数组.*/

int chess2[8][8];

int i, j;

for( i = 0; i < 8; i++ )

for( j = 0; j < 8; j++ )

chess2[i][j] = chess[i][j];

/*2.结束条件1,当结束条件成功,便成功找到了一次八皇后的置放方式

结束条件2,当已经没有安全的列,也会导致递归调用结束,返回上一级递归*/

if( row == 8 )  //成功找到一种放置方式,打印棋盘,返回到上一层递归,继续查找

{

printf( "\n" );   

for( i = 0; i < 8; i++ )  //打印棋盘

{

for( j = 0; j < 8; j++ )   

{

printf( "%2d", chess2[i][j]);

}

printf( "\n" );

}       

}

/*3.递归的主要功能实现,*/

else

for( i = 0; i< n; i++ ) //对本次递归的行的列依次进行安全检测,找到可以放置皇后的点.

{

if( !safety( row, i, chess ) )     //安全检测的数组需要是数组为原始数组chess而不是chess2,因为chess2可能被修改

{

for( j = 0; j < 8; j++ )

chess2[row][j] = 0; //先清空本列,可能由于本层递归失败的分支已经改变了本层的chess2数组,因此将本列清0

chess2[row][i] = 1;     //当chess2[row][i]安全时,将chess2数组的当前位置放置皇后  ,即设置为1 

eight_queen( row+1, n, chess2 );//递归调用下一行

}

 //若遍历本列,没有找到合法的落子点,则返回上一级递归,上一级继续循环,查找合法的落子点.

}   

}

}

 

 

算法设计与分析实验课3-2

 

递归理解

解决思路:

循环在矩阵中找到待匹配字符串的第一个字符,找到后,对该元素的四个方向进行判断,找到是否存在下一个待匹配字符.若找到,则进行下一层递归,若没有找到,返回上一层递归,在矩阵中,循环开始步骤.

递归条件:

  • 结束条件(找到满足字符串匹配路径或者无路可走)
  • 每次都接近结束条件

 

算法设计:

  • 分支:最多四条分支.最少0条分支.
    • 分支的结束判断为该分支四周无匹配点或无路可走.
    • 分支的递归条件为该方向满足下一个匹配点.
  • 方向:在递归过程中解决