前言
本文主要介绍栈的基本原理,建立在栈的基础上对递归的原理加以阐述。
一、栈的原理
我们都曾经在高中阶段学习过进制转化算法和秦九韶算法,表面上看,因为二者都是处理多项式(把10进制数n转化为p进制数实际上等价于n=)但深层次看来,实际上二者都使用了递归,或者说栈的思路。
那么栈是什么呢?泛泛而谈,是只能在一端进行插入删除操作的逻辑结构。比方说,对一个数组,我们只有一个指针(head)描述数组的实际大小,新输入(入栈)数组的数要先跟指针申请,让他上移一位,“腾出”一个空间。移除(出栈)一个数也要告知指针,让他向下移动一位,以声明“这个出栈的数已经不复存在”。有的时候指针腾不出空间,就会报错“上溢”(overflow),有的时候指针指到了a[0]之下的空间,也会报错“下溢”(underflow)。
我们可以看见:对于一个栈,操作head并不能影响栈所能达到的最大容量(n)。
head下移,并没有真的删除刚才的元素,只有再次入栈才会替换他。
栈基于数组可以存储,但实际上也可以只利用head指针,而不关心存储了什么。
他无疑就是一个逻辑结构。不是说数组真的只能单向操作,而是我们用栈思维将他串联起来。
标准的出入栈函数定义如下:这并不难理解
虽然按照定义上溢是>=n,下溢是<=0,但是没有人会定义一个长度为0的栈,且出入栈只能逐个增减head的“值”,所以条件只要判断head==n,即满栈为真,就不允许元素再入栈。只要条件判断head==0为真,即空栈为真,就不可以再出栈。
二、栈的实例
我们用最经典的火车调度为例:
图片来自《信息学奥赛一本通》:
一眼就能看出来,车站就是一个“栈”;
如果12345入,假设35241出
火车不能穿透前方的车,正常行驶,1号车会始终在最前方。
想要3号车最先出来,必须想办法让3出现在最前面,这通过栈来实现。
因为“后进栈先出栈”,进栈后123(A视角)就变成了321(B视角)。
3号车在1,2号车后面,只有1,2号车都进入栈内,3号车才能成为第一个出栈的元素 。
接下来只有4先进栈,5才能先进栈再出栈,成为第二个出栈的元素。
接下来4必须在2之前出去,但是假设要求2先出栈,故不可能,这个假设就是不可能的。
三、递归的原理与实例
一般定义递归为自身调用自身的函数,但我们还要想清楚为什么要自己调用自己。
递归就是通过栈来构建的,比如说秦九韶算法,人的思路是这样进行的;
图片来自百度百科:
实际上,以求解一个n次多项式的值为例,假设值为f(n)
f(n)=f(n—1)*x+c(n);
然后f(n-1)不知道,再把它写成
f(n-1)=f(n-2)*x+c(n-1);
以此类推,
直到f(1)=f(0)*x+c(1);
f(0)=c;终止递归。
我们不断调用自身,实质上是把f(n),f(n-1)……f(0)的表达式和变量由先到后压进栈内,然后凭借递归终止条件,把最后入栈的f(0)出栈,之后依次把高次的表达式出栈,直到返回f(n)的值。
我们之所以对递归感到怀疑,是因为不清楚其中的涉及栈的历程。
先对秦九韶算法代码实现如下:
例子,计算4*x^4+3*x^3+2*x^2+1*x+1,x=5
秦九韶算法的计算顺序与人阅读多项式的顺序一致,最内层括号内是最高次项的系数,这一过程可以很容易手写。计算机算法对于系数的输入顺序也是从高次到低次,从“左”到“右”。
运行结果:答案为2931
the end
参考资料:百度百科词条——秦九韶算法(代码为本文作者原创)
信息学奥赛一本通——栈
活动地址:CSDN21天学习挑战赛