数据结构之栈和队列

目录

一.栈

栈的定义

进栈出栈的不同情况

栈的顺序存储结构

结构定义

进栈操作

出栈操作

共享空间

基本概念

 结构定义

进栈操作

出栈操作

栈的链式存储结构(链栈)

结构定义

 进栈操作

 出栈操作

四则运算表达式求值

二.队列

队列的定义

循环队列

队列的顺序存储结构

结构定义

 初始化

 入队操作

 出队操作

 求队长

队列的链式存储结构

结构定义

进栈操作

出栈操作


一.栈

栈的定义

栈:栈其实就是一张特殊的线性表,他是一张只能在一头做插入和删除操作的线性表。

栈的特点:数据元素先进后出。

栈顶top:能够做插入和删除操作的一端。(top指向栈顶元素数组的下标)

空栈:不含任何数据元素的栈;规定top=-1。

插入操作叫:进栈、压栈、入栈。

删除操作叫:出栈、弹栈。

进栈出栈的不同情况

栈的特点是后进先出,那么不同的进栈方式就会对应不同的出栈方式。以下我们来看一个例子:

问题:现在有A、B、C三个元素依次放入栈中,有多少种不同的出栈方式?

我们已经知道栈的出栈只能是从栈顶一次出,那么不同的出栈方式其实是取决于不同的进栈方式的。下面我们来讨一下。

①:A B C 依次进入,对应的出栈顺序是:C B A

②:A进A 出,B进B出,C进C出,对应的出栈顺序:A B C

③:A B进,B A出,C进C出,对应的出栈顺序是:B A C 

④:A B进,B出,C进,C A 出,对应的出栈顺序是: B C A

⑤:A进,A 出,B C 进,C B 出,对应的出栈顺序是:A C B

栈的顺序存储结构

栈的顺序存储可以对比线性表的顺序存储。

结构定义

typedef int SElemType;
typedef struct{
	SElemType data[MAXSIZE];
	int top;
}SqStack;

进栈操作

算法步骤:

  1. 判断栈是否已满
  2. 如果未满,栈顶指针移向下一个位置
  3. 将要插入的元素存在栈顶
typedef int Status;
Status push(SqStack *S,SElemType e){
	if(S->top==MAXSIZE-1)//栈满 
	return ERROR;
	S->top++;//栈顶挪向下一个位置 
	S->data[S->top]=e;//将e存到栈顶 
	return OK;	
} 

出栈操作

算法步骤:

  1. 判断栈是否为空
  2. 如果不空,返回将要删除位置的值
  3. top指针指向前一个位置
Status pop(SqStack *S,SElemType *e){
	if(S->top ==-1)//栈空 
	return ERROR;
	*e=S->data[S->top ];//记录将要删除的位置的值 
	S->top --;//栈顶指针向下移动一位 
//	free();没有动态分配不用释放内存 
	return OK;
} 

共享空间

基本概念

两栈共享空间:用一个数组存两个栈,两个栈的栈底分别为数组的两头。让两个栈的元素向中间延伸。

栈空:top1=-1,top2=MAXSIZE-1(MAXSIZE为数组长度)

栈满:top1+1=top2

 结构定义

typedef struct{
	SElemType data[MAXSIZE];
	int top1;
	int top2;
}SqDoubleStack; 

进栈操作

Status push(SqDoubleStack *S,SElemType e, int StackNumber){//用StackNumber区分是对栈1进行操作还是对栈2进行操作
	if(S->top1-1==S->top2)//栈满 
	return ERROR;
	if(StackNumber==1){//对1栈进行操作 
		S->top1++; 
		S->data [S->top1 ]=e;
	}
	else if(StackNumber==2){//对栈2进行操作
		S->top2 --;
		S->data [S->top2 ]=e;
	}
	return OK;
}

出栈操作

Status pop(SqDoubleStack *S,SElemType *e, int StackNumber){
	if(S->top1 ==-1&&S->top2 ==MAXSIZE-1)//栈空 
	return ERROR;
	if(StackNumber==1){
		*e=S->data [S->top1];
		S->top1--;
	}
	else if(StackNumber==2){
		*e=S->data [S->top2];
		S->top2--;
	}
	return OK;
}

栈的链式存储结构(链栈)

结构定义

typedef struct LinkStack{
	SElemType data;
	struct LinkStack *next;
	int num;//记录表长 
}LinkListNode,*LinkListStack;
	//链表的头指针就相当于栈顶,不用再定义头指针,就把栈顶当作头指针来用 

 进栈操作

Status push(LinkListStack S,SElemType e){
	//LinkListStack top; 
	LinkListStack p;
	p=(LinkListStack)malloc(sizeof(LinkListNode));//为新节点分配空间 
	p->next =S->next ;  
	S->next=p;
	p->data =e;
	S->num++; 
	return OK;
}

 出栈操作

Status pop(LinkListStack S,SElemType *e){
	if(S->next ==NULL)  
	return ERROR;
    LinkListStack p;
	p=S->next ;
	*e=p->data ;
	S->next =p->next ;
	free(p);
	S->num --;
	return OK;	
}

四则运算表达式求值

二.队列

队列的定义

队列:一张只能在表头做删除操作,只能在表尾做插入操作的线性表。

如果把栈比作一个有瓶底的瓶子,那么队列就是一个没有瓶底的瓶子。栈只能在瓶口操作,队列在瓶底放入东西,在瓶口拿出东西。

队头:做删除操作的一头。

队尾:做插入操作的一头。

特点:先进先出

循环队列

由于在普通队列中,当队列头部的元素出队后,头指针后移,但头部空出的位置无法再利用,导致队列的空间浪费。所以出现了循环队列,循环队列通过使用数组,将队列的头尾连接在数组的两端,使得当队列尾到达数组的末尾时,它可以从数组的开始位置重新开始,形成一个循环。

循环队列:循环队列是一种基于数组或链表实现的队列数据结构,其特点在于队列的尾部和头部相邻,形成一个循环。

循环队列的两个指针:一个是队头指针(front),用于指向队列的第一个元素,另一个是队尾指针(rear),用于指向队列中最后一个元素的下一个位置

队列为空:front=rear=0;

队列为满:(rear+1)%QueueSize=front;(QueueSize为队列的最大空间)

队列长度:lehgth=(rear - front + QueueSize)%QueueSize;

队尾后移:(rear + 1)%QueueSize;

队头后移:(front + 1)%QueueSize;

队列的顺序存储结构

结构定义

typedef int Elemtype;
typedef struct{
	Elemtype data[MAXSIZE];
	int front,rear;
}SqQueue;

 初始化

Status InitQueue(SqQueue *Q){
	Q->front =0;
	Q->rear =0;
    return OK;	
}

 入队操作

Status EnQueue(SqQueue *Q,Elemtype e){//用*Q才能够通过指针传递队列,并且 EnQueue 函数能够修改原始队列。
	if((Q->rear+1)%MAXSIZE==Q->front)
	return ERROR;
	Q->data[Q->rear]=e;
	Q->rear=(Q->rear +1)%MAXSIZE;
	return OK;
}

 出队操作

Status DeQueue(SqQueue *Q,Elemtype *e){
	if(Q->front ==Q->rear )
	return ERROR;
	*e=Q->data[Q->front];
	Q->front =(Q->front +1)%MAXSIZE;
	return OK;
	
}

 求队长

int QueueLength(SqQueue Q){
	return (Q.rear -Q.front +MAXSIZE)%MAXSIZE;
}

队列的链式存储结构

链队列:对链表头做删除操作,对链表尾做插入操作的特殊链表。

front指针指向链表的头节点,rear指向链表的最后一个节点。

结构定义

typedef struct QNode{
	QElemType data;
	struct QNode *next;
}QNode,*QueuePtr;

typedef struct{
    QueuePtr front,rear;	
}LinkQueue; 

进栈操作

Status EnQueue(LinkQueue *LQ,QElemType e){
	QueuePtr p;
	p=(QueuePtr)malloc(sizeof(QNode));
	LQ->rear->next =p;
	LQ->rear =p;
	return OK;
}

出栈操作

Status DeQueue(LinkQueue *QL,QElemType *e){
	if(QL->front==QL->rear )//队列为空 
	return ERROR;
	QueuePtr p;
	p=QL->front->next ;
	*e=p->data ;
	QL->front->next =p->next ;
	if(QL->rear ==p)//如果p节点就是队尾 
	QL->rear=QL->front; //将rear指向头节点,front就是头节点 
	free(p);
	return OK;
}

注意这里用malloc和free函数要有头文件#include <stdlib.h>

  • 17
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值