大话数据结构--栈的应用

120 阅读3分钟

「这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战」。

前言

废话不多,数据结构必须学! 每天更新一章,一篇写不完的话会分成两篇来写~

资料获取

image.png

4.7栈的作用

用数组或链表直接实现功能不就行了吗?干吗要引入栈这样的数据结构呢?这个问题问得好。其实这和我们明明有两只脚可以走路,干吗还要乘汽车、火车、飞机一样。理论上,陆地上的任何地方,你都是可以靠双脚走到的,可那需要多少时间和精力呢?我们更关注的是到达而不是如何去的过程。栈的引入简化了程序设计的问题,划分了不同关注层次,使得思考范围缩小,更加聚焦于我们要解决的问题核心。反之,像数组等,因为要分散精力去考虑数组的下标增减等细节问题,反而掩盖了问题的本质。所以现在的许多高级语言,比如Java、 C#等都有对栈结构的封装,你可以不用关注它的实现细节,就可以直接使用Stack的push和pop方法,非常方便。

4.8栈的应用—递归

栈有一个很重要的应用:在程序设计语言中实现了递归。那么什么是递归呢? ​ 当你往镜子前面一站,镜子里面就有一个你的像。但你试过两面镜子一起照吗?如果A、B两面镜子相互面对面放着,你往中间一站,嘿,两面镜子里都有你的千百个“化身”。为什么会有这么奇妙的现象呢?原来,A镜子里有B镜子的像,B镜子里也有A镜子的像,这样反反复复,就会产生一连串的“像中像”。这是一种递归现象!

哈哈哈好有意思啊!

4.8.1 斐波那契数列实现

就是那个兔子生兔子的问题啦,原来在b站学习的时候都会有讲这个例子~

image-20211113163225826

斐波那契数列的特点就是:前面相邻两项之和,构成了后一项

用迭代实现

 int main( )
 {
     int i;
     int a[40];
     a[0]=0;
     a[1]=1;
     printf ("%d ",a[0]) ;
     printf ("&=%d ",a[1]) ;
     for (i=2;i< 40;i++ )
     {
         a[i]= a[i-1] + a[i-2];
         printf ("%d ",a[i] ) ;
     }
     return 0;
 }

用递归实现

 int Fbi ( int i)
 {
     if(!i<2)
         return i== 0?0 :1;
     return Fbi (i-1)+ Fbi (i-2) ;/*这里Fbi就是函数自己,它在调用自己*/ 
 }
 ​
 int main ( )
 {
     int i; 
     for (int i= 0;i < 40;i++ )
         printf ("&d "Fbi(i)) ;
     return 0;
 ​

image-20211113172405042

4.8.2递归定义

在高级语言中,调用自己和其他函数并没有本质的不同。我们把一个直接调用自己或通过一系列的调用语句间接地调用自己的函数,称做递归函数。

当然,写递归程序最怕的就是陷入永不结束的无穷递归中,所以,每个递归定义必须至少有一个条件,满足时递归不再进行,即不再引用自身而是返回值退出。比如刚才的例子,总有一次递归会使得i<2的,这样就可以执行return i的语句而不用继续递归了。

对比了两种实现斐波那契的代码。迭代和递归的区别是:迭代使用的是循环结构,递归使用的是选择结构。递归能使程序的结构更清晰、更简洁、更容易让人理解,从而减少读懂代码的时间。但是大量的递归调用会建立函数的副本,会耗费大量的时间和内存。迭代则不需要反复调用函数和占用额外的内存。因此我们应该视不同情况选择不同的代码实现方式。