数据结构复习栈和队列

2023-12-20 11:34:00

栈和队列都是在线性表的基础上,加上限制条件,栈是先进后出(FILO)的逻辑结构,队列是先进先出(FIFO)的逻辑结构。

两者都可以用顺序存储和链式存储的方式来存储,但栈最好用顺序存储,队列最好用链式存储。

typedef int DataType;
//sequence list:?
typedef struct SeqStack {
	DataType* data;
	int top;
	int max;
}SeqStack;

可以这样用动态存储,也可以用数组实现静态存储,队列的实现就是typede int DataType(我们再来想一下这个typedef的作用,目的是为了将整个数据结构中的数据域分离出来方便处理,在typedef数据结构的时候就可以直接用DataType data来声明一个数据域)typedef struct LineNode{DataType data;? struct LineNode*next}LineNode;? typedef struct Line{LineNode*first;? LineNode*rear}Line;即可(也就是声明一个链表,但这时候我们需要用到尾指针,队列用链表来实现,插入的时候是尾插法,删除的时候从头部删除)。

基本操作:初始化、增、删、判空

栈:

void InitStack(SeqStack* pS)
{
	pS->top = -1;
	pS->max = 0;
	pS->data = NULL;
}

bool StackEmpty(SeqStack S)
{
	if (S.top == -1) {
		return true;
	}
	else {
		return false;
	}
}

void Expand(SeqStack* pS)
{
	DataType* p = realloc(pS->data, (pS->max + 2) * sizeof(DataType));
	if (p == NULL) {
		perror(p);
		return;
	}
	pS->data = p;
	pS->max += 2;
}

void Push(SeqStack* pS, int n)
{
	if (pS->top + 1 >= pS->max) {
		Expand(pS);
	}
	pS->data[++pS->top] = n;
}

void Pop(SeqStack* pS, int* n)
{
	if (StackEmpty(*pS)) {
		return;
	}
	*n = pS->data[pS->top--];
}

队列的链式存储实现代码较为简单,我们用数组来实现一下循环队列:循环队列的front和rear每一次增加都要这样写(front=(front+1)%MaxSize,比如MaxSize是6,数组的下标就是0-5,(5+1)%6=0,就回归到0了,实现了循环队列中循环二字,注意1%6=1)

typedef int DataType;

typedef struct SeqLine {
	DataType data[MaxSize];
	int rear;
	int front;
}SeqLine;

void InitLine(SeqLine* pL)
{
	pL->front = 0;
	pL->rear = 0;
}

bool IsEmpty(SeqLine L)
{
	if (L.front == L.rear) {
		return true;
	}
	return false;
}

void InLine(SeqLine* pL, int n)
{
	//
	if ((pL->rear + 1) % MaxSize == pL->front) {
		printf("\n");
		return;
	}
	pL->data[pL->rear] = n;
	pL->rear = (pL->rear + 1) % MaxSize;
}

void OutLine(SeqLine* pL, int* n)
{
	if (IsEmpty(*pL)) {
		printf("?\n");
		return;
	}
	*n = pL->data[pL->front];
	pL->front = (pL->front + 1) % MaxSize;
}

栈和队列中还有几个重点习题,比如栈的应用中的括号匹配问题,用两个队列实现栈,用两个栈实现队列;

栈的应用:

1、括号匹配问题,((())){},从左向右扫描,遇到左括号就存入栈中,遇到右括号就出栈看是否匹配,直到最后扫描完,若栈为空则匹配成功

2、逆波兰公式和波兰公式,这是我们将中缀表达式转化为后缀表达式和前缀表达式的方式,比如有一个中缀表达式,我们手算将其转化为后缀表达式,遵循左优先原则,从左向右依次扫描整个中缀表达式,比如A+B这个式子,A是左操作数,B是右操作数,+是操作符,则写成AB+即可,这是手算经历,若机算的话,我们能遇到的有操作数、操作符、界限符三个,若遇到操作数我们直接将其写到后缀表达式中,若遇到操作符则将栈中所有比此时扫描到的操作符要高级或者等于的操作符依次弹出栈,弹出至栈为空或者遇到界限符为止,若遇到界限符则入栈,遇到右界限符则依次弹出操作符至左操作符,这就是中缀转后缀的一个机算方式。后缀计算的机算方式是从左至右依次扫描整个后缀表达式,遇到操作数就放入栈中,遇到操作符就弹出栈中两个数据,先拿出的就是右操作数,后拿出的是左操作数,计算后再压入栈顶,最后得到的栈顶的数据就是最终结果。还有一个比较重要的机算方式就是中缀表达式直接计算的机算方式,需要用两个栈,分别是操作数栈和操作符栈,最后的结果再操作数栈中,遇到操作数就压入操作数栈中,遇到操作符和界限符就按照我们处理中缀转后缀中对操作符和界限符的处理方式来处理即可。

用两个队列实现栈:入栈的时候朝不为空的队列中插入,出栈时将不为空的队列中数据全转移到另一个队列中去,剩余一个元素就是栈顶元素,后面Pop的时候也是一样,因为队列在转移的时候不会改变数据的顺序,这是队列的特性

用两个栈实现队列:分为插入栈和出数据的栈,我们插入元素的时候要将元素插入到插入栈中去,不能插入到出数据的栈中,否则会导致数据乱掉,删除的时候我们首先要判空,若不为空则看出数据的栈是否为空,若为空就将插入栈的所有的数据移过来,若不为空则删除出数据的栈中的数据即可。

至此,线性表部分告一段落,后面还有扩充的数组相关的知识,线性表部分包括了最基础的顺序表(顺序实现的线性表,分为静态实现和动态实现)和链表(链式存储实现的线性表)以及受限制的线性表,栈和队列,难度不大但细节多,需要多加记忆和理解。

文章来源:https://blog.csdn.net/weixin_74442828/article/details/135097977
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。