目录
前言:
递归比较循环的优势:
1.递归和循环都是重复性质的操作,递归有清晰的层次:
2.循环结构回溯,中断继续操作较为困难:
3.总结(应用场景):
如何去写递归代码:
1.对递归代码的理解:
2.广义表的创建:
3.广义表的输出:
总结:
来总结一下,首先是递归什么情况下好用:
递归到底是什么:
递归的核心思路:
部分同学在写广义表的创建和输出时,在对递归代码的阅读,理解和写递归代码时有些许困难和迷茫。这篇博客主体是递归,循环会作为递归比较的客体,比较简略。
首先会说明一些自己在递归上的理解,和相较于循环,递归的优势(不同于网上搜出来的优点缺点,那些东西讲的太简洁了,太抽象了,少了些废话,对于我们知识和见识不够深入的学生来说,有些难以体会和理解),我会主要根据自己写代码的经验讲实际的应用,最后我会完全从头到尾的演示我在写广义表的创建和输出的时候,思路和思考方式,过程演示,希望对同学们有帮助。
循环构建层次可以循环中嵌套循环,而对于层次数量不定的构建,很困难(我不会)。特别是在有分支层次的时候:比如树的遍历,图的遍历。我自己在用循环写分支有层次的时候很难进行下去。
在具有分支层次的时候,递归可以调用自身中断当前操作,在递归结束后继续执行后续操作;而循环得通过嵌套,而countiue, break,跳过当前循环,和退出循环,都很难做到像递归一般,接着处理后续操作。
例如在树的遍历当中,一个结点深度遍历到底了,需要回溯到上一个分支点继续深入,递归可以完美执行这一步操作,但是循环比较难实现。、
循环很难对层次,分支层次进行操作,此时往往使用递归可以很好的解决。
将某一堆重复的操作抽象出来,比如我们从小听的一个故事:
从前有座山,山里有座庙,庙有老和尚和小和尚,老和尚给小和尚讲故事:从前有……;
这个便是定义结构体一座山,定义一个结构体庙在山里,定义两个和尚在庙里,方法便是老和尚创建“山”这个结构体类型,并递归调用自身,传参山.庙.老和尚,无限递归。
typedef struct { struct shan * old; //老和尚struct shan * young; //小和尚
}temple; //庙typedef struct shan{temple *temple; //庙
}mountain; //山mountain * story(mountain *old) {//从前有座山(山开空间),山里有座庙 old = (mountain *)malloc(sizeof(mountain));//庙里有老和尚和小和尚(给庙temple开空间) old->temple = (temple *)malloc(sizeof(temple));//老和尚给小和尚讲故事:从前有座山(小和尚赋值为stroy,stroy传参为山里庙里老和尚) old->temple->young = story(old->temple->old); return old->temple->young; //无限递归
}
总结下来便是:只操作一遍,只对第一遍操作负责,剩下的重复操作交给递归。对广义表来说,只用创建一个结点,孩子兄弟链的sublist指针,和link指针交给递归。
先创建函数,确定好参数列表:纸上写好假设一个广义表g = (a,(b,(c)),d);
typedef struct node {int tag;union{ElemType data;struct node *sublist; }val;struct node *link;
}GLNode;GLNode *CreateGL(char *s, int *loca) {//大前提:字符串s是正确的广义表的括号表达式//loca用于指向字符串s中的字符
}
画出广义表g的层次结构图(这次用孩子兄弟链结构):
我们要写递归代码,我们首先要明确中心思路,我们只对一个结点负责,我们只需要写好对于一个结点的创建,剩下的交给递归。
GLNode *CreateGL(char *s, int *loca) {GLNode *g;if(s[*loca] != '