栈的分析和详解

栈的定义:
栈是限定仅在尾部进行插入和删除操作的线性表,我们把允许插入和删除操作的一端叫做 “栈顶”,另一端叫做 “栈底”。
栈是一种 “先进后出,后进先出” 的线性表。
如图:
在这里插入图片描述

栈的存储结构分为:顺序结构和链式结构。
顺序结构就是使用数组的方式来存储,结构通常如下:
数组 + 当前栈顶的下标
在这里插入图片描述
这里的 “Data” 我们给的是一个 struct 的结构,数据可自定义,这里定义的是int,如下:
在这里插入图片描述
栈的通用的方法结构如下,参数不唯一,主要介绍方法:
在这里插入图片描述

顺序存储分析:
优点:代码结构简单方便。
缺点:需要用一个固定空间的数组来存储数据,如果栈满了,就需要继续申请更大的空间去存储,这个过程比较耗时,而且,如果栈是一个小栈,但是开辟了大量空间,就会导致空间浪费。

链式结构就是使用链表的方式来存储;
栈顶就是链表的头节点,每次进行插入删除的操作时,我们可以直接对链表的头部进行操作。
栈存储结构如下:头指针 + 链表长度
在这里插入图片描述
节点结构如下,当前值 + 下一个节点指针:
在这里插入图片描述
方法具体同顺序表,这里不再多做介绍。

链表存储分析:
优点:节省空间,要多少创建多少个节点,按需分配,不会造成空间浪费,也不用担心扩容的问题。
缺点:代码相较于顺序表复杂一点。

建议:如果栈的使用过程中元素变化不可预测,会忽大忽小的变化,建议使用链表,如果变化可控,且占用空间不大的情况下建议使用顺序表。

栈的应用—递归
例子:斐波那契数列
在这里插入图片描述

上图我们了解了斐波那契数列,那么接下来让我们用代码实现一下:
两种方式:循环 + 递归
循环:

void Fibonacci(int n)
{
	if (n < 0)
	{
		return;
	}
	if (n == 0)
	{
		cout << 0;
	}
	else if (n == 1)
	{
		cout << 1;
	}
	else
	{
		int pre = 1;
		int ppre = 0;
		cout << ppre << " ";
		cout << pre << " ";
		int temp = 0;
		for (int i = 2; i < n; i++)
		{
			temp = pre + ppre;
			cout << temp << " ";
			ppre = pre;
			pre = temp;
		}
	}
}

递归:

int FibonacciNew(int n);

int main()
{
	int fbiNum = 10;
	for (int i = 0; i < fbiNum; i++)
	{
		cout << FibonacciNew(i) << " ";
	}
}

int FibonacciNew(int n)
{
	if (n <= 0)
	{
		return 0;
	}
	else if( n == 1)
	{
		return 1;
	}
	return FibonacciNew(n - 1) + FibonacciNew(n - 2);
}

总结,递归和循环的区别是:
迭代使用的是循环结构,递归使用的是选择结构。递归可以让代码更清晰,更简洁,更容易理解。但是大量的递归调用会建立函数的副本,会耗费大量的时间和内存,迭代不需要反复的调用函数占用额外的空间。
从空间复杂度的角度上来分析:
递归的空间复杂度是O(lgN),简单理解一点的话,N可以理解为你压栈的次数,即递归的次数。
迭代的空间复杂度是O(1)。所以,如果递归的次数较大的情况下建议使用循环的方式解决问题。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值