特殊的线性表:栈的基本操作(顺序栈、链栈)

版权声明:转载请注明出处~~~ https://blog.csdn.net/lesileqin/article/details/88381142

栈和队列是两种特殊的线性结构,从数据结构的角度来看,栈和队列也是线性表。他们的特点在于仅限在表头或者表尾进行插入或者删除的操作。栈和队列都是特殊的线性结构,所以他们的实现方式也包括顺序存储和链式存储两种方式。


栈(stack)

栈是限定仅在表尾进行插入和删除操作的线性表。

因此我们把允许插入和删除的一段叫做栈顶(top),另一端称作栈底(bottom)。没有任何数据元素的栈叫做空栈

如图所示,栈的插入与删除过程已经很明确了,看的出来栈是一种后进先出(Last In First Out,LIFO)的结构。

  • 栈的插入操作,叫做进栈,也称压栈、入栈。
  • 栈的删除操作,叫做出栈,也可以称作弹栈。

栈的抽象数据类型

ADT 栈(STACK)
{
	DATA
		同线性表。元素具有相同的类型,相邻元素具有前驱后继关系。
	OPERATION
		InitStack(&S)	构造一个空栈S
		DsetroyStack(&S)	若栈存在,销毁栈
		ClearStack(&S)	将栈清空
		StackEmpty(S)	若栈存在元素返回False,否则返回True
		GetTop(S)	得到栈顶数据元素
		Push(&S,e)	若栈存在,将新元素e插入到栈顶
		Pop(&S,&e)	删除栈顶元素,并用e返回其值
		StackLength(S)	返回栈的元素个数
		StackTraverse(S)	从栈底到栈顶依次对S的每个数据元素进行访问		
} 

顺序栈的表示和实现

顺序栈的存储结构:

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

base为栈底指针,初始化之后,始终指向栈底的位置;若base的值为NULL,则表明栈不存在。top为栈顶指针,其初值指向栈底,入栈时*top++;出栈时*top--。

顺序栈的初始化

【算法步骤】

  • 为顺序栈动态分配一个最大容量为MAXSIZE的数组空间,使base指向这段空间的基地址,即栈底
  • 栈顶指针top初始化为base,表示栈为空
  • stacksize置为栈的最大容量MAXSIZE
//构造一个空栈 
Status InitStack(SqStack &S)
{
	S.base=new SElemType[MAXSIZE];
	if(!S.base)
		exit(OVERFLOW);
	S.top=S.base;
	S.StackSize=MAXSIZE;
	return true;
}

顺序栈的入栈    

【算法步骤】

  • 判断栈是否已满,若满则返回false
  • 将新元素压入栈顶,返回true
//在栈顶插入新元素e 
Status Push(SqStack &S,SElemType e)
{
	if(S.top-S.base==S.StackSize)
		return false;
	*S.top++=e;
	return true;
}

顺序栈的出栈

【算法步骤】

  • 判断栈是否为空,若空则返回false
  • 栈顶指针减一,栈顶元素出栈
//顺序栈的出栈 
Status Pop(SqStack &S,SElemType &e)
{
	if(S.top==S.base)	
            return false;		//栈空
	e=*--S.top;
	return true; 
}

取栈顶元素

【算法步骤】

  • 若栈非空时,此操作返回当前栈顶元素值,栈顶指针不变
//取栈顶元素 
SElemType GetTop(SqStack S)
{
	if(S.base!=S.top)
		return *(S.top-1);
}

注:由于顺序栈和顺序表一样,受到最大容量的限制,虽然可以在“满员”时重新分配空间扩大容量,但工作量较大,应该尽量避免。


链栈的表示和实现

通常链栈用单链表来表示,链栈的结点结构和单链表的结构相同。要了解单链表的基本操作请点我

链栈的存储结构

typedef struct StackNode{
	SElemType data;			//数据域 
	struct StackNode *next;	        //指针域 
}StackNode,*LinkStack;
  • 由于栈的主要操作是在栈顶插入和删除,显然以链表的头部作为栈顶是最方便的,而且没必要附加一个头结点

链栈的初始化

【算法步骤】

  • 构造空栈,栈顶指针置为空即可
Status InitStack(LinkStack &S)
{
	S=NULL;
	return true;
}

链栈的入栈

【算法步骤】

  • 为入栈元素e分配空间,用指针p指向
  • 将新结点的数据域置为e
  • 将新结点插入到栈顶
  • 修改栈顶指针为p
Status Push(LinkStack &S,SElemType e)
{
	StackNode *p=new StackNode;	//生成新结点 
	p->data=e;			//将结点的数据域赋值为e
	p->next=S;			//将新结点插入栈顶
	S=p;				//修改栈顶指针为p
	return true; 
}

链栈的出栈

【算法步骤】

  • 判断栈是否为空,若空返回false
  • 将栈顶数据域赋值给e
  • 临时保存栈顶位置,以备释放
  • 栈顶指针指向下一个地址
  • 释放原栈顶指针,返回true
Status Pop(LinkStack &S,SElemType &e)
{
	if(S==NULL)
		return false;
	e=S->data;		//将栈顶赋给e
	StackNode *p=S;		//用p临时保存栈顶元素空间,以备释放 
	S=S->next;		//修改栈顶指针
	delete p;		//释放原栈顶元素空间
	return true; 
}

取栈顶元素

【算法步骤】

  • 如果栈顶不为空,返回栈顶数据域
SElemType GetTop(LinkStack S)
{
	if(S)
		return S->data;
}

遍历链栈

【算法步骤】

  • 建立新指针p指向S(栈顶)
  • 当p不为空时执行:你想要进行的步骤(可求长,可逐个销毁每个结点等等),p指向下一个地址
void StackTraverse(LinkStack S)
{
	StackNode *p=S;
	while(p)
	{
		此处可以写对每个结点进行的操作 
		p=p->next;
	}
}

队列的基本操作请访问:https://blog.csdn.net/lesileqin/article/details/88410689


博客内容借鉴于:

①《数据结构》  作者:严蔚敏

②《大话数据结构》 作者:程杰

猜你喜欢

转载自blog.csdn.net/lesileqin/article/details/88381142