一、递归函数的非递归实现
递归函数本身就是用栈来实现的,只是我们看不见而已。
1.当一个函数在调用另一个函数时,要做三件事情:
a)保存实参,返回地址等信息(保护现场);
b)为被调用函数的局部变量分配存储区;
c)将控制转移到被调用函数的入口。
2.从被调用函数返回调用函数之前,也要做三件事情:
a)保存被调用函数的计算结果,并恢复现场;
b)释放被调函数的数据区;
c)将控制转回到调用函数。
*其中函数调用自己就是递归的过程。
我们可以知道:函数调用是通过栈实现的,而递归的本质是函数调用->递归可以用栈消除。
3.函数执行过程
![](https://i-blog.csdnimg.cn/blog_migrate/82f8536758287366af43a3fda5eeea99.png)
流程分析:如图,在main函数中运行到r:f1()时,此时有三个过程,r此时是一个断点,我们将r入栈,然后将前面所有程序走过的有参数的值保留起来,再将控制权转给f1函数;之后的f1函数也是如此,在f2函数走完之后,我们再将栈中的t出栈在f1继续完成f1函数,之后r再出栈,完成主函数的流程。
再如快速排序的函数quicksort:
![](https://i-blog.csdnimg.cn/blog_migrate/29a1e8ba034250eaec78798eef540b21.png)
那么,我们如何用非递归的形式实现递归呢?答案肯定是栈。
![](https://i-blog.csdnimg.cn/blog_migrate/9ca1cc09c8696ae9ec8dd3a8c25cde3a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7a5d68c01d6e57572d5cbf93e1675807.png)
流程:
我们先确定目标为第一个元素,如图为6,此时数组排序为0-5;
之后我们将6与右边(也就是其他所有元素)作比较,算出比它小的和比它大的元素各有多少,如图,左边下标是0-2,右边是4-5;
然后该数组有了两个区域,我们再对两个区域分别进行刚才相同的步骤,如此循环,可以看见,该步骤和递归的方式原理其实是一样的。
二、符号的平衡检测
在这方面我们主要解决如何使用栈解决符号的配对问题,即判断栈顶的括号是否和栈底的符号相配对。
1.算法部分(CheckBalance()函数)
①首先创建一个空栈;
②从源程序中读入符号;(读入符号不像是读入字符,有些符号由多个字符组成,读入符号的过程更多)
③如果读入的符号是开符号,那就将其进栈;
④如果读入的符号是一个闭符号,但栈是空的,则出错,否则,将栈中的符号出栈;
⑤如果出栈的符号和读入的闭符号不匹配,出错;
⑥继续从文件中读入下一个符号,非空则转向③,否则转向⑦;
⑦如果栈非空,报告出错,否则括号配对成功。
备注:其中②可以使用GetNextSymbol函数,第⑥步可以使用CheckMatch()函数。
2.读取符号(GetNextSymbol())的步骤:
①读取一个字符ch1;(Nextchar())
②如果ch1='/',则再读取一个ch2;
如果ch2='*',则跳过紧着着的Comment;(SkipComment())
如果ch2='/',则跳过本行的Comment;
否则,回退ch2;(PutBackChar())
③如果ch1!='/',则判断:
如果ch1='\'或者'''',则跳过字符常量或字符串变量;
如果ch1='{'或‘}’等,则返回字符ch1。
符号的平衡性检测实际上就是检测开闭符号(比如说括号)的平衡性。