数据结构(二)—栈

数据结构(二)—栈

一、栈的概念及特点

概念

(stack)是限定仅在表尾进行插入或删除操作的线性表,其表尾端称为栈顶(top),表头端称为栈底(bottom),不含元素的空表称为空栈。

特点

后进先出(LIFO,Last In First Out)

image-20200405230451961

基本操作

  • 初始化
  • 入栈
  • 出栈
  • 取栈顶元素

分类

根据存储结构不同,我们又可以把栈分为顺序栈链栈

下面我们分别来实现这两种存储结构的栈。

二、顺序栈实现

顺序栈一般是用数组来实现,存在两个指针,栈顶、栈底指针,分别指向数组的尾部和头部,如下图:

image-20200406201829220

栈空的条件即是top==base。比较好理解,下面直接上代码:

存储结构

//栈-顺序栈实现
#include<iostream>
using namespace std;

int const N=100;
//顺序栈的存储结构
typedef int SElemType;
typedef struct 
{
	SElemType *base;//栈底指针
	SElemType *top;//栈顶指针
	int stackSize;//栈可用的最大容量
}SqStack;

初始化

//栈初始化
void InitStack(SqStack &s)
{
	s.base=new int[N];//为顺序栈动态分配一个最大容量为N的数组空间
	s.top=s.base;//top初始为base,表示空栈
	s.stackSize=N;//stacksize置为栈的最大容量N
} 

入栈

//入栈,插入元素data为新的栈顶元素
void Push(SqStack &s, SElemType data)
{
	if(s.top-s.base==s.stackSize)
	{//栈满 
		cout<<"栈已满!"<<endl;
		return;
	}
	*s.top=data;//将元素data入栈
	*s.top++;//栈顶指针加1
} 

出栈

//出栈,删除栈顶元素,用data返回其值
void Pop(SqStack &s,SElemType &data)
{
	if(s.base==s.top)
	{
		cout<<"栈为空!"<<endl;
		return;
	}
    data=*s.top;
	*s.top--;//栈顶指针减1
}

取栈顶元素

//返回s的栈顶元素,不修改栈顶指针
int GetTop(SqStack &s)
{
	if(s.base!=s.top)//栈非空
		return *(s.top-1);
}

验证

int main()
{
	SqStack myStack;
	InitStack(myStack);
	Push(myStack,1);
	Push(myStack,2);
	Push(myStack,3);//将1,2,3依次入栈
	cout<<"栈顶元素:"<<GetTop(myStack)<<endl;//获取当前栈顶元素
	int a;
	Pop(myStack,a);//出栈
	cout<<"弹出栈顶元素后,现栈顶元素为"<<GetTop(myStack)<<endl;//获取当前栈顶元素
	return 0;
}

运行以上代码后,运行结果如下:

image-20200406203019501

三、链栈实现

链栈一般采用单链来表示:

image-20200406210200768

存储结构

//链栈实现
#include<iostream>
using namespace std; 

//链栈的存储结构
typedef char ElemType;
typedef struct StackNode
{
	ElemType Data;//数据域
	StackNode *Next;//指针域
}StackNode,*LinkStack;

初始化

//初始化,构造一个空栈S,栈顶指针置空
void InitStack(LinkStack &S) 
{
	S=NULL;
}

入栈

与顺序站不同的是,链栈在入栈前不需要判断栈是否满,只需要为入栈元素动态分配一个结点空间,如下图:

image-20200406210346949

//入栈,在栈顶插入元素data
void Push(LinkStack &S,ElemType data)
{
	StackNode *p=new StackNode();//生成新结点
	p->Data=data;//将新节点数据域置为data
	p->Next=S;//将新节点插入栈顶
	S=p;//修改栈顶指针为p
} 

出栈

和顺序栈一样,出栈是需要判断栈是否为空,不同的是,链栈在出栈后需要释放出栈元素的栈顶空间,如下图:

image-20200406210533789

//出栈,删除S的栈顶元素,并用data返回其值
void Pop(LinkStack &S,ElemType &data)
{
	if(S==NULL)
	{//栈为空
		cout<<"栈为空!"<<endl;
		return;
	}
	data=S->Data;//将栈顶元素赋给data
	StackNode *p=S;//用p临时保存栈顶元素空间,以备释放
	S=S->Next;//修改栈顶元素
	delete p;//释放原栈顶元素的空间 
} 

取栈顶元素

//返回S栈顶元素,不修改栈顶指针
ElemType GetTop(LinkStack &S)
{
	if(S!=NULL)//栈非空
		return S->Data;
}

验证

//打印栈 
void PrintStack(LinkStack &S)
{
	if(S!=NULL)
	{
		StackNode *p=S;
		while(p!=NULL)
		{
			cout<<p->Data<<"	";
			p=p->Next;
		}
		cout<<"
";
	}
}

int main()
{
	LinkStack LS;
	InitStack(LS);//初始化栈
	Push(LS,'a');
	Push(LS,'b');
	Push(LS,'C');//将a b C依次入栈
	PrintStack(LS);//打印当前栈
	ElemType a;
	Pop(LS,a);//将C出栈
	PrintStack(LS);//打印当前栈
	cout<<"栈顶元素为:"<<GetTop(LS);//当前栈顶元素元素
	return 0;
}

运行结果如下:

image-20200406211203870

四、总结

栈的实现相对来说比较简单,主要掌握顺序栈和链栈的实现即可~

参考资料:《数据结构(C语言)(第2版)》 严蔚敏等著

写文不易~因此做以下申明:

1.博客中标注原创的文章,版权归原作者 煦阳(本博博主) 所有;

2.未经原作者允许不得转载本文内容,否则将视为侵权;

3.转载或者引用本文内容请注明来源及原作者;

4.对于不遵守此声明或者其他违法使用本文内容者,本人依法保留追究权等。

原文地址:https://www.cnblogs.com/gentlesunshine/p/12649685.html