数据结构与算法(6)

栈的定义

 

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

我们把允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。栈又称为后进先出(Last In First Out)的线性表,简称LIFO结构。

栈是一个线性表,栈具有线性关系,即前驱后继关系。只不过是一种特殊的线性表。定义中说在 表尾进行插入和删除操作,这里表尾是只栈顶而不是栈底。栈的特殊之处就在于限制了这个线性表的插入和删除位置,他始终在栈顶进行。这也使得栈底是固定的,最先进栈的只能在栈底。

栈的插入操作叫做进栈,也称压栈、入栈。

栈的删除操作,叫做出栈,也称弹栈。

ADT 栈(stack)
Data
    同线性表元素具有相同的类型,相邻元素具有前驱和后继关系
Operation
    InitStack(*S):初始化操作,建立一个空栈S
    DestoryStacks(*S):若栈存在,则销毁它
    ClearStack(*S):将栈清空
    StackEmpty(S):若栈为空,返回ture,否则返回false
    GetTop(S,*e):若栈存在且非空,用e返回S的栈顶元素
    Push(*S,e):若栈S存在,插入新元素e到栈S中并成为栈顶元素
    POP(*S,*e):删除栈中栈顶元素,并用e返回其值
    StackLength(S):返回栈S的元素个数
endADt

栈的顺序储存结构及实现

栈的顺序储存结构其实于是线性表顺序储存的简化,我们简称为顺序栈。可以使用数组来实现,我们可以使用数组下标为0的一端来作为栈底,我们定义一个top变量来指示栈顶变量在数组中的位置,若储栈的长度为StackSize,则栈顶位置必须小于StackSize,当栈存在一个元素时,top等于0,因此通常把空栈的判定条件定为top等于-1.

下面为栈的结构定义:

typedef int SElemType;//SElemType类型视情况而定 
//顺序栈结构 
typedef struct
{
	SElemType data[MAXSIZE];
	int top;//用于栈顶指针 
}SqStack;

进栈操作Push:

//插入新元素e为新的栈顶元素 
Status Push(SqStack *S,SElemType e)
{
	if(S->top == MAXSIZE-1)//栈满 
	{
		return ERROR;
	}
	S->top++;//栈顶指针增加1 
	S->data[S->top]=e;//将新插入元素赋值给栈顶空间 
	return OK;
 } 

出栈操作Pop:

//若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR 
status Pop(SqStack *S,SElemType *e) 
{
	if(S->top == -1)
		return ERROR;
	*e=S->data[S->top];//将要删除的栈顶元素赋值给e 
	S->top--;//栈顶指针减1 
	return OK;
}

两栈共享空间

如果有两个相同类型的栈,我们为他们各自开辟了一个数组空间,如果中一个栈满了,另一个栈还空着,这样就造成了空间的浪费。我们可以用一个数组来存放两个栈,充分利用数组的储存空间。

数组有两个端点,两个栈有两个栈底,让一个栈的栈底为数组的始端,就是的数组下标为0处,另一个栈的栈底为数组的末端,也就是下标为数组长度n-1处,如果增加元素就是向数组的中间位置延伸。

top1和top2是栈1和栈2的栈顶指针,如果栈1为空时,就是top1等于-1时,而当top2等于n时就是栈2为空时。如果两个指针之间按相差1时,即top1+1==top2时为栈满。

两栈共享空间的代码如下:

//两栈共享空间结构 
typedef struct
{
	SElemType data[MAXSIZE];
	int top1;//栈1栈顶指针 
	int top2;//栈2栈顶指针 
}SqDoubleStack;

对于两栈共享空间的push方法,我们除了要插入元素值参数之外,还需要有一个判断为栈1还是栈2的栈号参数stackNumber。

插入元素的代码如下:

//插入元素e为新的栈顶元素 
Status Push(SqDoubleStack *S,SElemtype e , int stackNumber)
{
	if(S->top1 +1==S->top2 )//栈已满,不能在push新元素 
		return ERROR;
	if(stackNumber==1)//栈1有元素入栈 
		S->data[++S->top1]=e;//若是栈1则先top1+1后给数组元素赋值 
	else if(stackNumber==2)//栈2有元素入栈 
		S->data[--S->top2]=e;//若是栈2则先top2-1后给数组元素赋值 
	return OK;
}

对于两栈共享空间的pop方法,参数就只是判断栈1栈2的参数stackNumber,代码如下:

//若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR 
status Pop(SqDoubleStack *S,SElemType *e,int stackNumber)
{
	if(stackNumber==1)
	{
		if(S->top1=-1)
			return ERROR;//说明栈1已是空栈,溢出 
		*e=S->data[S->top1--]//将栈1的栈顶元素出栈 
	}
	else if(stackNumber==2)
	{
		if(S->top2==MAXSIZE)
			return ERROR;//说明栈2已是空栈,溢出 
		*e=S->data[S->top2++];//将栈2的栈顶元素出栈 
	}
	return OK;
}

栈的链式储存存结构及实现

栈的链式储存结构简称栈链。

一般来说栈顶放在单链表的头部,另外已经有栈顶在顶部,那么头节点就失去意义了,使用对于栈链来说一般是不需要头节点的。

栈链的结构代码如下:

//栈链结构 
typedef struct StackNode
{
	SElemType data;
	struct StackNode *next;
}StackNode,*LinkStackPtr;

typedef struct
{
	LinkStackPtr top;
	int count;
}LinkStack;

对于栈链的进栈push操作,假设元素值为e的新结点是s,top为栈顶指针,代码如下:

//插入元素e为新的栈顶元素 
Status Push(LinkStack *S,SElemType e)
{
	LinkStackPtr s=(LinkStackPtr)malloc(sizeof(StackNode));
	s->data=e;
	s->next =S->top //把当前的栈顶元素赋值给新结点的后继 
	S->top =s//将新结点s赋值给栈顶指针 
	S->count++;
	return OK;
}

对于链栈的出栈pop操作,先假设变量p用来储存要删除的结点,将栈顶指针下移一位,最后释放p即可,代码如下:

//若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR 
Status Pop(LinkStack *S,SElemType e)
{
	LinkStackPtr p;
	if(StackEmpty(*S))
		return ERROR;
	*e=S->top->data;
	p=S->top;//将栈顶结点赋值给p 
	S->top =S->top->next;//使得栈顶指针下移一位,指向后一结点 
	free(p);//释放结点p 
	S->count--;
	return OK;
}

如果栈的使用过程中元素变化不可预料,有时很小,有时非常大,那么最好用栈链,反之,它的变化在可控范围内,使用顺序栈更好一点。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值