王道--数据结构第三章 栈、队列和数组

在这里插入图片描述
在这里插入图片描述

↓  如果有五个数据元素入栈的话,构成可能的出栈方式有42种↓

在这里插入图片描述


顺序栈的实现

顺序栈:用顺序存储的方式实现栈
顺序栈的缺点:栈的大小不可改变

在做题过程中一定要注意栈顶指针top指向的是栈顶元素的位置还是栈顶元素之后的那个位置。
代码3.1.1

//王道第三章
//顺序栈
#include <iostream> 
#include <stdio.h>
#include <stdlib.h>
using namespace std;

#define MaxSize 10      //定义栈中元素的最大个数
typedef struct{
	int data[MaxSize];  //静态数组存放栈中元素
	int top;			//栈顶指针
}SqStack;				//Sq---Squence 顺序

//初始化栈
void InitStack(SqStack &S){
	S.top=-1;			//初始化栈顶指针为-1
}

//判断栈是否为空栈
bool StackEmpty(SqStack S){
	if(S.top==-1) return true;
	else return false;
}

//新元素进栈
bool Push(SqStack &S,int e){
	//首先判断是否满栈,如果满栈就报错
	if(S.top==MaxSize-1) return false;
	S.top++;				//指针先加一
	S.data[S.top]=e;
	return true;
}

//出栈操作
bool Pop(SqStack &S,int &x){
	if(S.top==-1) return false; //空栈报错
	x=S.data[S.top];			//栈顶元素先出栈
	S.top--;					//指针-1,在逻辑上删除数据
	return true;
}

//读栈顶元素
bool Pop(SqStack &S,int &x){
	if(S.top==-1) return false; //空栈报错
	x=S.data[S.top];			//x记录栈顶元素
	return true;
}

int  main(){
    SqStack S;			//声明一个顺序栈(分配空间)
    InitStack(S);
	return 0;
}

可以通过共享栈的方式提高一整片分配给栈的空间的利用率
逻辑上实现了两个栈,但物理上他们又是占用了同一片的存储空间,能够提高空间资源的利用率

#define MaxSize 10      //定义栈中元素的最大个数
typedef struct{
	int data[MaxSize];  //静态数组存放栈中元素
	int top0;			//0号栈顶指针
	int top1;			//1号栈顶指针
}ShStack;				//Sh---Share 共享

//初始化共享栈
void InitStack(ShStack &S){
	S.top0=-1;			//初始化栈顶指针
	S.top1=MaxSize;
	return;
}

//判断是否满栈
bool isFull(ShStack S){
	if(S.top0+1==S.top1) return true;
	else return false;
}
int  main(){
    ShStack S;			//声明一个共享栈(分配空间)
    InitStack(S);		//初始化共享栈
	return 0;
}

在这里插入图片描述


链栈

链栈:用链式存储的方式实现栈
(联想单链表的头插法,和在头节点处删除操作。)
类似的方法我们可以建立带头结点的链栈和不带头节点的链栈
代码3.1.2

//王道第三章
//链栈(带头结点)
#include <iostream> 
#include <stdio.h>
#include <stdlib.h>
using namespace std;
typedef struct StackNode{
	int data;  //静态数组存放栈中元素
	struct StackNode *next;
}StackNode,*Stack;

//初始化栈
void InitStack(Stack &S){
	S->next=NULL;			//初始化栈
}

//判断栈是否为空栈
bool StackEmpty(Stack S){
	if(S->next==NULL) return true;
	else return false;
}

//新元素进栈
bool Push(Stack &S,int e){
	StackNode *s=(StackNode *)malloc(sizeof(StackNode));
	s->data=e;
	s->next=S->next;
	S->next=s;
	return true;
}

//出栈操作
bool Pop(Stack &S,int &x){
	if(S->next==NULL) return false; //空栈报错
	x=S->next->data;			//x记录栈顶元素
	StackNode *s=S->next;
	S->next=s->next;
	free(s);
	return true;
}

//读栈顶元素
bool Pop(Stack S,int &x){
	if(S->next==NULL) return false; //空栈报错
	x=S->next->data;			//x记录栈顶元素
	return true;
}

int  main(){
    Stack S;			//声明一个顺序栈
    InitStack(S);
    StackEmpty(S);
	return 0;
}

在这里插入图片描述


队列

在这里插入图片描述
在这里插入图片描述


顺序队列(循环队列)
代码3.1.3

//王道第三章
//顺序队列
#include <iostream> 
#include <stdio.h>
#include <stdlib.h>
using namespace std;

#define MaxSize 10      //定义队列中元素的最大个数
typedef struct{
	int data[MaxSize];  //静态数组存放队列中的元素
	int front,rear;		//队头指针和队尾指针
}SqQueue;				//Sq---Squence 顺序

//初始化队列
void InitQueue(SqQueue &Q){
	//让队头指针front指向队头
	//让队尾指针rear指向队尾的后一个元素
	//初始时队头指针和队尾指针都指向0
	Q.front=0;
	Q.rear=0;
}

//判断队列是否为空队列
bool QueueEmpty(SqQueue Q){
	//Q.front==Q.rear是判断空队列的条件
	if(Q.front==Q.rear) return true;
	else return false;
}

//入队
bool EnQueue(SqQueue &Q,int e){
	//首先判断队列是否已满,如果满就报错
	if((Q.rear+1)%MaxSize==Q.front) return false;
	Q.data[Q.rear]=e;
	Q.rear=(Q.rear+1)%MaxSize;	//队尾指针加一,取模,利用循环队列
	return true;
}

//出队操作(删除第一个队头元素,并用x返回)
bool DeQueue(SqQueue &Q,int &x){
	if(Q.rear==Q.front) return false; //空队列报错
	x=Q.data[Q.front];			//队头元素出队
	Q.front=(Q.front+1)%MaxSize;//指针-1,在逻辑上删除数据
	return true;
}

//读栈顶元素
bool Pop(SqQueue &Q,int &x){
	if(Q.rear==Q.front) return false; //空队列报错
	x=Q.data[Q.front];			//x记录队头元素
	return true;
}

int  main(){
    SqQueue Q;			//声明一个顺序队列(顺序存储)
    InitQueue(Q);
	return 0;
}

在这里插入图片描述
循环队列
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

考试的时候需要注意题目的队尾指针是指向队尾元素的还是队尾元素的后一个元素的,两者之间进行操作时的处理方法不同
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


链式队列
在这里插入图片描述


链式队列 = 链队列 (带/不带头节点)
代码3.1.4

//王道第三章
//链式队列 = 链队列 (带/不带头节点)
#include <iostream> 
#include <stdio.h>
#include <stdlib.h>
using namespace std;

typedef struct LinkNode{//链式队列的结点
	int data;             //用于存放队列中的元素
	struct LinkNode *next;//用于指向队列的下一个结点
}LinkNode;

typedef struct{			  //链式队列
	LinkNode *front,*rear;//队列的队头指针和队尾指针
}LinkQueue;

//初始化队列(带头结点)
void InitQueue(LinkQueue &Q){
	//初始时队头指针和队尾指针都指向头节点
	Q.front=Q.rear=(LinkNode *)malloc(sizeof(LinkNode));
	Q.front->next=NULL;
}

//判断队列是否为空队列(带头结点)
bool QueueEmpty(LinkQueue Q){
	//Q.front->next==NULL是判断链队列是否为空队列的条件
	//Q.front==Q.rear也能判断
	if(Q.front==Q.rear) return true;
	else return false;
}

//入队(带头结点)
bool EnQueue(LinkQueue &Q,int e){
	LinkNode *s=(LinkNode *)malloc(sizeof(LinkNode));
	if(s==NULL) return false;
	s->data=e;
	s->next=NULL;
	Q.rear->next=s;		//新节点插入表尾
	Q.rear=s;			//更新表尾结点
	return true;
}

//出队操作(带头结点)(删除第一个队头元素,并用x返回)
bool DeQueue(LinkQueue &Q,int &x){
	if(Q.front==Q.rear) return false; //空队列报错
	LinkNode *q=Q.front->next;
	x=q->data;			    //x存储要删除结点的数据
	Q.front=q->next;		//修改队列的队头	
	if(Q.rear==q) Q.rear=NULL;//此次是最后一个结点出队
	free(q);				//释放删除结点的空间
	return true;
}

//初始化队列(不带头结点)
void NInitQueue(LinkQueue &Q){
	//初始时队头指针和队尾指针都指向NULL
	Q.front=Q.rear=NULL;
}

//判断队列是否为空队列(不带头结点)
bool NQueueEmpty(LinkQueue Q){
	//Q.front==NULL是判断链队列是否为空队列的条件
	//如果rear指向的是队尾元素也可以判断rear是否指向NULL
	if(Q.front==NULL) return true;
	else return false;
}

//入队(不带头结点)
bool NEnQueue(LinkQueue &Q,int e){
	LinkNode *s=(LinkNode *)malloc(sizeof(LinkNode));
	if(s==NULL) return false;
	s->data=e;
	s->next=NULL;
	if(Q.front==NULL){
	//如果等于代表是第一个结点
		Q.front=s;
		Q.rear=s;
	}else{
		Q.rear->next=s;		//新节点插入表尾
		Q.rear=s;			//更新表尾结点
	}
	
	return true;
}

//出队操作(不带头结点)(删除第一个队头元素,并用x返回)
bool NDeQueue(LinkQueue &Q,int &x){
	if(Q.front==NULL) return false; //空队列报错
	LinkNode *q=Q.front;
	x=q->data;			    //x存储要删除结点的数据
	Q.front=q->next;		//修改队列的队头
	if(Q.rear==q) Q.front=NULL,Q.rear=NULL;//此次是最后一个结点出队
	free(q);				//释放删除结点的空间
	return true;
}

int  main(){
    LinkQueue Q;			//声明一个顺序队列(顺序存储)
    InitQueue(Q);
	return 0;
}

在这里插入图片描述

双端队列

下面的类型在选择题中很常见。
从左到右观察可能输出的序列,第一个数输出时,意味着比他小的数都已经入栈或入队了,应该有一定的排列方式,然后再根据输入受限或者输出首先或者单端输入输出的情况,思考有没有能满足题目输出的插入方式,如果没有的话,该输出序列就是非法的。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

栈的应用—括号匹配问题

在这里插入图片描述
在这里插入图片描述
扫描到匹配的括号,就出栈相对应的匹配括号
一旦扫描到不匹配的括号就可以停下来,就可以判断这组括号是非法的
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


后缀表达式的特点:后缀表达式的符号排列顺序与中缀表达式中的符号生效的次序相同


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意:上面这张PPT里面的“左操作数”“右操作数”“左优先原则”“右优先原则”是DIY的,王道自己杜撰的,不能真的写在简答题里面
在这里插入图片描述
上面的栈是用来存储当前还不能确定运算顺序的运算符的(初加减乘除外还包括左括号,但不包括右括号,右括号不会出现入栈的情况)
手写伪代码的方式转换中缀表达式为后缀表达式,手写推理符号进出栈的过程。
注意如果这里的运算过长、过为复杂需要防止用来存储运算符号的栈溢出。

中缀表达式的计算机运算:
在这里插入图片描述

****
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


二维数组也具有随机存取的特性


在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

普通矩阵

在这里插入图片描述

对称矩阵

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意对称矩阵计算线性实际存储的位置时

①明确到底是用上三角区(i>j)外带主对角线还是下三角区(i<j)外带主对角线存储。
如果是上三角区域可以通过对称矩阵的性质计算转化为下三角区域的计算,也可以不转化,直接按照上三角区域的方式计算。
②开辟线性存储区域的角标是从0开始的还是从1开始的。
③是采用行优先原则存储还是列优先原则存储。

在这里插入图片描述

三角矩阵

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

三对角矩阵的压缩存储

三对角矩阵又称带状矩阵

如何通过三角对称矩阵的坐标位置映射到线性的存储位置

在这里插入图片描述

如何通过三角对称矩阵的线性的存储位置映射到坐标位置

在这里插入图片描述

在这里插入图片描述

稀疏矩阵的压缩存储

在这里插入图片描述
↑顺序存取(三元组的方法)缺点:失去了随机存取的特性

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃小酥肉的小波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值