顺序栈、链栈基本操作

文章目录

  • 一、 顺序栈
  • 二、链栈
  • 三、顺序栈和链栈的对比

一、 顺序栈

顺序栈的基本概念、初始化、入栈、出栈、清空、销毁

顺序栈存储方式:同一般线性表的顺序存储结构完全相同,利用一组地址连续的存储单元依次存方自栈底到栈顶的数据元素,栈底一般在低地址端。

  • 附设top指针,指示栈顶元素在顺序栈中的位置。但是为了操作方便,通常top指示真正的栈顶元素之上的下标地址。
  • 另设base指针,指示栈底元素在顺序栈中的位置。
  • 另外,用stacksize表示栈可使用的最大容量。

判断栈满栈空

空栈:base = =top是栈空的标志
栈满:top-base= =stacksize

栈满时的处理方法

1、报错,返回操作系统
2、分配更大的空间,作为栈的存储空间,将原栈内容移入新栈(缺点就是太费时)

使用数组作为顺序栈存储方式的特点:
简单、方便但易产生溢出(数组大小固定)

  • 上溢(overflow):栈已经满,又要压入元素
  • 下溢(underflow):栈已经空,还要弹出元素

注:上溢是一种错误,使问题的处理无法进行;而下溢一般认为是一种结束条件,即问题处理结束

先表明一下预定义常量及类型:

#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define true 1
#define false 0
typedef int Status;

顺序栈的表示

#define MAXSIZE 100	//顺序栈存储空间初始分配量
typedef struct{
 SElemType *data;	//栈顶指针
 SElemType *top;	//栈尾指针
 int stacksize;		//栈可用最大容量
 }SqStack;

顺序栈初始化

Status InitStack(SqStack &s){//构造一个空栈
S.base = new SElemType{MAxSIZE];
//或用c语言语法:S。base=(SElemType*)malloc(MAXSIZE*sizeof(SElemType));
if(!S.base)//S.base是栈中的第一个元素
	exit(OVERFLOW);//空间分配失败
S.top=S.base;//栈顶指针等于栈底指针
S.stacksize=MAXSIZE;//stacksize置为最大容量MAXSIZE	

顺序栈入栈

Status Push(SqStack &S,int e){//插入e,为新的栈顶元素
if(S.top-S.base==S.stacksize)//栈满
*S.top=e;//取栈顶指针所指空间存e
S.top++;//栈顶指针加一
//上面两句可以合并成一句*S.top++=e;因为算法优先级问题,现存e再指针加一
return OK;

顺序栈出栈

Status Pop(SqStack &S,int e){//删除S的栈顶元素,用e返回其值
if(S.top==S.base)	//栈空
	return ERROR;	//若空则出错(下溢)
--S.top;		//栈顶指针减一
e==*S.top;		//将栈顶元素赋给e,带*表示指针所指的那块空间
//同样的,上面两句可以合并为e==*--S.top;
return OK;		

顺序栈取栈顶元素

int GetTop(SqStack S){//返回S的栈顶元素,不修改栈顶指针
if(S.top!=S.base)	//栈不为空
	return *(S.top-1);	//返回栈顶元素的值,栈顶指针不变,即还在栈顶的上方

【算法补充】

顺序栈判断栈是否为空:

Status StackEmpty(SqStack S)//若栈为空,返回TURE,否则返回FLALSE
if(S.top==S.base)
	return TRUE;
else
	return FALSE;
}	

求顺序栈长度:

int StackLength(SqStack S)
{
	return S.top-S.base;
}	

清空顺序栈(空间还在,只是删除元素):

Status ClearStack(Sqstack S){
if(S.base)	//如果base存在,即栈存在 
	S.top=S.base;//把base的值赋值给top
return OK;	

销毁顺序栈(空间不在):

Status DestroyStack(SqStack &S){
if(S.base){
	delete S.base;//
	S.stacksize=0; //栈内空间的个数为0
	S.base=S.top=NULL;//指针为空
}
return OK;	
}

二、链栈

用链式存储结构实现的栈。
链栈的结点结构与单链表的结构相同,在此用SNode表示;

链栈的表示:

  • 链栈是运算受限的单链表,只能在链表头部进行操作
typedef struct SNode{
Selem data;
struct SNode *next;//嵌套定义
}SNode,*LInkStack;//栈的结点类型。*Linkstack是指针类型
LinkStack S;

链栈中指针的方向,一般栈顶元素指向前驱元素,以此类推,目的是操作方便

  • 链表的头指针就是栈顶
  • 不需要头结点
  • 基本不存在栈满的情况,只要内存有空间
  • 空栈相当于头指针指向空,S=NULL;
  • 插入和删除仅在栈顶处执行

链栈的初始化

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

【算法补充】
判断链栈是否为空

Status StackEmpty(LinkStack S){
if(S==NULL)//头指针为空就是空栈
	return TRUE;
else
	return FALSE;

链栈的入栈

插的新元素放入栈顶

Status Push(LinkStack &S,int e){
SNode *p=new SNode	//生成新结点p
p->data=e;		//将新结点数据域值为e
p->next=S;		//将新结点插入栈顶,p的指针域指向下面结点地址也就是原来的头指针S,
S=p;			//修改栈顶指针,也就是p变为S,S指向了新结点
return OK;

链栈的出栈

Status Pop(LinkStack &S,int &e){//删除栈顶S的栈顶元素,用e返回其值
if(S==NULL)	//栈空,无元素可以删除
	return ERROR;
e=S->data;	//将栈顶元素赋给e,以便取出
SNode *p=S;	//p指向S即用p临时保存栈顶元素空间,以备释放
S=S->next;	//修改栈顶指针
delete p;	//释放原栈顶元素空间
return OK;
}	

取栈顶元素

int GetTop(LinkStack S){
if(S!=NULL)
	return S->data;
}	

三、顺序栈和链栈的对比

相同:时间复杂度一样,均为O(1)
不同:

  • 顺序栈需事先确定一个固定的长度,可能会存在内存空间浪费的问题,优势是存取是定位很方便
  • 链栈则要求每个元素都有指针域,这同时也增加了一些内存开销,但对于栈的长度无限制

那么我们如何选择呢?
如果栈的使用过程中元素变化不可预料,有时很小,有时非常大,那么最好是用链表,反之,如果变化在可控范围内,建议使用顺序栈。

你可能感兴趣的:(数据结构)