数据结构之栈与队列

联系

栈和队列是一类操作受限制的线性表(即限定性线性表),其特殊性在于限制了插入和删除等操作的位置。
在栈中,用户只能在指定的一端插入和删除元素,因此具有后进先出的特性。
在队列中,用户只能在一端插入元素而在另一端删除元素,因此呈现先进先出的特性。

在这里插入图片描述
先来补充几个概念:
栈顶: 允许进行插入、删除操作的一端
栈底: 表的另一端
空栈: 没有元素的栈
进栈: 栈的插入操作
出栈: 栈的删除操作
栈分为两种:顺序栈和链栈
顺序栈:
顺序栈存储结构的定义:

#define Stack_Size 50
typedef struct
{
	StackElementType elem[Stack_Size]; /*用来存放栈中元素的一维数组*/
	int top;						   /*用来存放栈顶元素的下标*/
}SeqStack;

1.初始化

void InitStack(SeqStack *S)
{
	S->top=-1;
}

2.进栈
进栈时,首先判断当前栈是否已满,如果栈已满,还要进栈就会发生上溢。

int Push(SeqStack *S,StackElementType x)
{
	if(S->top==Stack_Size-1)
		return 0;
	S->top++;
	S->elem[S->top]=x;
	return 1;
}

3.出栈
出栈时,首先判断当前栈是否为空,如果栈空,还要出栈就会发生下溢。

int Pop(SeqStack *S,StackElementType *x)
{
	if(S->top==-1)
		return 0;
	else
	{
		*x=S->elem[S->top];
		S->top--;
		return 1;
	}
}

4.读栈顶元素

int GetTop(SeqStack *S,StackElementType *x)
{
	if(S->top==-1)
		return 0;
	else
	{
		*x=S->elem[S->top];
		return 1;
	}
}

补充: 多栈共享技术
背景:使用顺序栈,因为对栈空间大小难以准确估计,从而产生有的栈溢出,有的栈空间还很空闲的情况。为了解决这一问题,可以让多个栈共享一个足够大的数组空间,通过利用栈的动态特性(即栈底位置不变,栈顶位置动态变化)来使其存储空间相互补充,这就是栈的共享技术。最常用的是两个栈的共享技术,即双端栈。
具体方法:首先申请一个共享的一维数组空间S[M],将两个栈的栈底分别放在一维数组的两端,分别是0,M-1。由于两个栈顶是动态变化的,这样可以形成互补,使得每个栈可用的最大空间与实际使用的需求有关。
双端栈的存储结构定义如下:

#define M 100
typedef struct
{
	StackElementType Stack[M];		   /*Stack[M]为栈区*/
	StackElementType top[2];		   /*top[0]和top[1]分别为两个栈顶指示器*/
}DqStack;

链栈:
链栈的优点: 不必预先估计栈的最大容量,只要系统有可用空间,链栈就不会出现溢出。
链栈的存储结构定义:

typedef struct node
{
	StackElementType data;
	struct node *next;
}LinkStackNode;

1.进栈

int Push(LinkStack top,StackElementType x)
{
	LinkStackNode *temp;
	temp=(LinkStackNode *)malloc(sizeof(LinkStackNode));
	if(temp==NULL)					  /*申请空间失败*/
		return 0;
	temp->data=x;
	temp->next=top->next;
	top->next=temp;
	return 1;
}

2.出栈

int Pop(LinkStack top,StackElementType *x)
{
	LinkStackNode *temp;
	temp=top->next;
	if(temp==NULL)
		return 0;
	top->next=temp->next;
	*x=temp->data;
	free(temp);
	return 1;
}

队列

在这里插入图片描述
补充几个概念:
队尾: 允许插入的一端
队头: 允许删除的一端
队列有两种重要形式:循环队列(顺序存储)和链队列(链式存储)
循环队列:
假溢出:在队列的顺序存储结构中,随着部分元素的出队,数组前面会出现一些空单元,由于只能在队尾入队,使得上述空单元无法使用的现象。
循环队列就能很好的解决假溢出现象,使队列空间得到充分利用。
但同时又面临一个新的问题:如何判断队列是空还是满?
有两种方法:损失一个元素空间和增设一个标志量
采用第一种方法时:
判队空:rear == front
判队满:(rear+1) mod MAXSIZE ==front
在这里插入图片描述
循环队列的类型定义如下:

#define MAXSIZE 50
typedef struct
{
	QueueElementType element[MAXSIZE];	/*队列的元素空间*/
	int front;							/*头指针指示器*/
	int rear;							/*尾指针指示器*/
}SeqQueue;

1.初始化

void InitQueue(SeqQueue *Q)
{
	Q->front=Q->rear=0;
}

2.入队

int EnterQueue(SeqQueue *Q,QueueElementType x)
{
	if((Q->rear+1)%MAXSIZE==Q->front)	/*队满*/
		return 0;		
	Q->element[Q->rear]=x;				
	Q->rear=(Q->rear+1)%MAXSIZE;		/*重新设置队尾指针*/
	return 1;	
}

3.出队

int DeleteQueue(SeqQueue *Q,QueueElementType *x)
{
	if(Q->front==Q->rear)				/*队列为空*/
		return 0;
	*x=Q->element[Q->front];			
	Q->front=(Q->front+1)%MAXSIZE;		/*重新设置队头指针*/
	return 1;
}

链队列:
链队列中,队头指针front始终指向头结点,队尾指针rear指向最后一个元素。
链队列的定义:
通常将队头指针和队尾指针封装在一个结构体中,并将该结构体类型重新命名为链队列类型

typedef struct Node
{
	QueueElementType data;
	struct Node *next;
}LinkQueueNode;
typedef struct
{
	LinkQueueNode *front;
	LinkQueueNode *rear;
}LinkQueue;

1.初始化

int InitQueue(LinkQueue *Q)
{
	Q->front=(LinkQueueNode *)malloc(sizeof(LinkQueueNode));
	if(Q->front!=NULL)
	{
		Q->rear=Q->front;
		Q->front->next=NULL;
		return 1;
	}
	else
		return 0;						/*溢出*/
}

2.入队

int EnterQueue(LinkQueue *Q,QueueElementType x)
{
	LinkQueueNode *NewNode;
	NewNode=(LinkQueueNode *)malloc(sizeof(LinkQueueNode));
	if(NewNode!=NULL)
	{
		NewNode->data=x;
		NewNode->next=NULL;
		Q->rear->next=NewNode;
		Q->rear=NewNode;
		return 1;
	}
	else
		return 0;						/*溢出*/
}

3.出队

int DeleteQueue(LinkQueue *Q,QueueElementType *x)
{
	LinkQueueNode *p;
	if(Q->front==Q->rear)
		return 0;
	p=Q->front->next;
	Q->front->next=p->next;
	if(Q->rear==p)						/*如果队中只有一个元素p,则p出队后成为空队*/
		Q->rear=Q->front;
	*x=p->data;
	free(p);
	return 1;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值