栈__数据结构笔记

说明

本博客用于记录本人的学习历程,本人水平有限,如有错误,欢迎在评论区指出。
本博客中的代码均由C++实现。

如果你觉得看完这篇文章有收获,就动动小手点个赞吧!

在实际使用中,手写栈会很浪费时间,也容易出现错误。可以使用STL中封装好的stack,方便又快捷,附上stack的使用方法:

https://blog.csdn.net/SDAU_LGX/article/details/104730819

一. 栈的特点

  • 具有先进后出、后进先出的特点。
  • 栈是一种操作受限的线性表,只允许从一端插入和删除数据,这一端被称为栈顶,另一段被称为栈底。
  • 不含任何数据元素的栈被称为空栈。
  • 栈有两种存储方式,线性存储和链接存储(链表)。

栈的示意图

二、顺序存储

1. 顺序栈

栈的顺序存储结构被称为顺序栈,用数组来储存数据。需要确定的是用数组的那一段来做栈底,一般来说,使用下标为0的位置作为栈底。

顺序栈的实现

使用C++中的类来实现顺序栈,为了使用更加的方便,使用模板机制。

#include<iostream>
using namespace std;
const int MAX_SIZE=1e5;
template<typename T>
class SeqStack {
	int data[MAX_SIZE];
	int top;
public:
	SeqStack();//构造一个空栈
	~SeqStack();//析构
	void Push(T x);//入栈
	void Pop();//出栈
	bool Empty();//判断栈是否为空
	T GetTop();//返回栈顶元素
};

构造函数

构造一个空栈,将栈顶指针top赋值为-1

template<typename T>
SeqStack<T>::SeqStack()
{
	top = -1;
}

析构函数

顺序栈是静态分配内存,析构函数为空即可

template<typename T>
SeqStack<T>::~SeqStack()
{

}

入栈操作

先判断栈是否为满栈,若为满栈则不可插入,抛出异常。不满则栈顶指针top++,插入元素

template<typename T>
void SeqStack<T>::Push(T x)
{
	if (top == MAX_SIZE - 1)throw"满栈";
	data[++top]=x;
	return;
}

出栈操作

先判断是否为空栈,若空栈则不可出栈,抛出异常。不是空栈则top--

template<typename T>
T SeqStack<T>::Pop()
{
	T x;
	if (top == -1)throw"空栈";
	x = data[top--];
	return x;
}

判空操作

判断top是否为-1,若为-1则返回true,否则返回false

template<typename T>
bool SeqStack<T>::Empty()
{
	if (top == -1)return true;
	return false;
}

返回栈顶元素

判断是否为空栈,若为空栈则抛出异常,不是则返回data[top]

template<typename T>
T SeqStack<T>::GetTop()
{
	if (top == -1)throw"空栈";
	return data[top];
}

2. 双端栈(两栈共享空间)

双端栈就是用一个数组来储存两个栈,能有效地节省空间。让其中一个栈的栈底为数组的首端,另一个栈的栈底为数组的尾端,向中间延伸。

双端栈的实现

声明

const int MAX_SIZE = 1e5;
template<typename T>
class BothStack {
	int top1;
	int top2;
	T data[MAX_SIZE];
public:
	BothStack();//建立空栈
	~BothStack();//析构函数
	void Push(int i, T x);//入栈
	T Pop(int i);//出栈
	T GetTop(int i);//获取栈顶元素
	bool Empty(int i);//判断栈是否为空
};

构造函数

将两个栈顶指针都初始化为-1

template<typename T>
BothStack<T>::BothStack()
{
	top1 = -1;
	top2 = MAX_SIZE;
}

析构函数

利用数组储存数据,析构函数为空

template<typename T>
BothStack<T>::~BothStack()
{

}

入栈操作

首先判断是否满栈,然后再进行插入
这里注意判断满栈的条件是两个栈指针相邻,即 top1+1=top2
同时还要注意top指针是自加还是自减
以数组首为栈底的栈top1++,以数组尾为栈底的栈top2--

template<typename T>
void BothStack<T>::Push(int i, T x)
{
	if (top1 + 1 == top2)throw"满栈";
	if (i == 1)data[++top1] = x;
	if (i == 2)data[--top2] = x;
}

出栈操作

首先判断是否为空栈(判断要进行出栈操作的栈)
还要注意栈顶指针top的操作
以数组首为栈底的栈top1--,以数组尾为栈底的栈top2++

template<typename T>
T BothStack<T>::Pop(int i)
{
	if (i == 1)
	{
		if (top1 == -1)throw"空栈";
		return data[top--];
	}
	else if (i == 2)
	{
		if (top2 == MAX_SIZE)throw"空栈";
		return data[top++];
	}
}

获取栈顶元素

先判断是否为空,再返回栈顶元素就可

template<typename T>
T BothStack<T>::GetTop(int i)
{
	if (i == 1)
	{
		if (top1 == -1)throw"空栈";
		return data[top1];
	}
	else if (i == 2)
	{
		if (top2 == MAX_SIZE)throw"空栈";
		return data[top2];
	}
}

判断是否为空

判断top是否为-1

template<typename T>
bool BothStack<T>::Empty(int i)
{
	if (i == 1)
	{
		if (top1 == -1)return true;
		return false;
	}
	else if (i == 2)
	{
		if (top2 == MAX_SIZE)return true;
		return false;
	}
}

三、链接存储

4.链栈

栈的链接存储结构为链栈,一般用单链表表示。为了操作方便,以单链表的头部作为栈顶,同时不需要头结点。

链栈的实现

声明

template<typename T>
struct Node {
	T data;
	Node<T>* next;
};

template<typename T>
class LinkStack {
	Node<T>* top;
public:
	LinkStack();//构造一个空栈
	~LinkStack();//析构
	void Push(T x);//入栈
	T Pop();//出栈
	bool Empty();//判断栈是否为空
	T GetTop();//返回栈顶元素
};

构造函数

构造一个不带头结点的单链表,是top指针为空即可

template<typename T>
LinkStack<T>::LinkStack()
{
	top = NULL;
}

析构函数

回收申请的内存,和单链表的析构函数类似

template<typename T>
LinkStack<T>::~LinkStack()
{
	Node<T>* p = NULL;
	while (top)
	{
		p = top;
		top = top->next;
		delete p;
	}
}

入栈操作

由于是链式存储,所以不用判断是否为满栈

template<typename T>
void LinkStack<T>::Push(T x)
{
	Node<T>* s = new Node<T>;
	s->data = x;
	s->next = top;
	top = s;
}
算法描述:
先申请一下新节点,储存数据x
修改新节点的指针域指向top
top指针前移到新建立的结点

出栈操作

先判断栈是否为空,再进行操作

template<typename T>
T LinkStack<T>::Pop()
{
	if (top == NULL) throw"空栈";
	T x = top->data;
	Node<T>* p;
	p = top;
	top = top->next;
	delete p;
	return x;
}
算法描述:
先判断栈是否为空
把栈顶元素储存起来
栈顶指针后移
释放栈顶空间

获取栈顶元素

先判断是否为空,不为空则返回栈顶元素

template<typename T>
T LinkStack<T>::GetTop()
{
	if (top == NULL)throw"空栈";
	return top->data;
}

判断栈是否为空

判断top指针是否为空

template<typename T>
bool LinkStack<T>::Empty()
{
	if (top == NULL)return true;
	return false;
}

四、顺序栈和链栈的比较

可以发现,顺序栈的链栈的时间复杂度都为O(1),所以我们来比较空间性能。
顺序栈需初始化一个固定的长度,所以会有长度限制和空间浪费的现象。链栈不会出现满栈的情况,但是因为每个元素都需要一个指针域,所以产生了空间的额外开销。

所以当栈使用过程中元素个数变化不大时使用顺序栈,否则使用链栈。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值