数据结构 之 ~栈与队列~

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

我们将允许插入和删除操作的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。

栈又称后进先出(Last In First Out)的线性表,也就是说,栈具有线性关系,即前驱后继关系。又简称LIFO结构。

栈的插入操作(push):进栈,也称栈,入栈。

栈的删除操作(pop):出栈,也称栈。

插入删除操作如图所示:

 合法出栈数:

(5条消息) 栈和卡特兰数(Catalan number)_LolitaAnn的博客-CSDN博客_卡特兰数求出栈公式

凡是合法序列都遵循以下规律:即对于出栈序列中的每一个数字,在它后面的、比它小的所有数字,一定是按递减顺序排列的。

详见上面这篇博客。

栈的顺序存储结构

当栈存在一个元素时,top=0,因此常把空栈的判定条件定位top=-1;

同理,top=n时,栈满。

示例·pop:

int Pop(Stack *S,int *e){
    
    if(S->top==-1){ return ERROR; }
    *e=S->data[S->top];
    S->top--;
    return OK;

}

push同理可得;

两栈共享空间

如图4-5-1: 

pop操作:

常在两栈空间需求关系相反时使用。

栈的链式存储结构:

链栈:将单链表头指针与栈顶指针合二为一,则此时头结点失去意义,通常对链栈来说,不需要头结点。

空栈判定:top=NULL;

代码示例及详解:

#include<stdio.h>
#include<stdlib.h>

typedef struct StackNode {
	int data;
	struct StackNode* next;
}*LinkStackPtr/*ptr:pointer*/;

typedef struct LinkStack {
	LinkStackPtr top;/*top链栈结构体指针,StackNode*型*/
	/*和链表头指针无太大区别,和原先栈顶指针产生差异*/
	/*原先top只负责数组中的索引功能,记录值还是由数组完成的*/
	/*现在top是一个真正的指针,它指向栈顶元素的地址*/
	/*所以S->top->data是栈顶元素*/
	int cnt;//相当于原本的top,负责记录栈顶元素的位置
} LinkStack;

int Push(LinkStack *S, int e) {
	LinkStackPtr p = (LinkStackPtr)malloc(sizeof(struct StackNode)); //申请内存
	p->data = e;
	p->next = S->top;
	S->top = p;
	S->cnt++;//将栈顶拉高1
	return 1;//OK
}
//S->top:a[n-1]    S->top->next:a[n-2]
int Pop(LinkStack *S, int *e) {
	if (S->cnt == -1) {
		return 0;
	}
	LinkStackPtr p;
	*e = S->top->data;
	p = S->top;//one
	S->top = S->top->next;
	S->cnt--;
	free(p);//two    The steps one and two are important.
	return 1;
}

栈的应用:四则运算问题(带括号)

思路:1.利用栈进出运算符来将中缀表达式转换成后缀表达式

2.利用栈进出运算数字将后缀表达式处理出结果

队列

(queue)只允许在一端执行插入,而在另一端执行删除操作的线性表。

先进先出(FIFO),允许插入的一端称为队尾,允许删除的一端称为队头。

队列的顺序存储结构:

显然,队列的顺序存储结构较难满足我们对队列的要求(可以通过循环队列来进行优化),于是,我们考虑链式存储结构。

队列的链式存储结构(链队列):

参考博客:

1.exit函数

代码示例:

#include<stdio.h>
#include<stdlib.h>
typedef struct QNode {
	int data;
	struct QNode* next;
}*Qptr;

typedef struct {
	Qptr head, rear;
} LinkQueue;

int EnQueue(LinkQueue *Q, int e) {
	Qptr p = (Qptr)malloc(sizeof(struct QNode));
	
	if (!p)
		exit(EOVERFLOW);
	p->data = e;
	p->next = NULL;
	Q->rear->next = p;
	Q->rear = p;
	
	return 1;
}

int DeQueue(LinkQueue *Q, int* e) {
	Qptr p;
	//拥有头结点,故是->next->next
	if (Q->head == Q->rear)
		return 0;
	p = Q->head->next;
	*e = p->data;
	Q->head->next = p->next;
	
	if (Q->rear == p)
		Q->rear = Q->head;
	free(p);
	
	return 1;
	
}

小结:

其实二者本质上是一种特殊一些的单链表而已。

链栈不需要带头结点,而链队列带头结点更为便捷。

下篇文章讲串~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值