栈与队列、矩阵压缩


栈与队列都是受限的线性表,其 逻辑结构相同,均为——线性表。

顺序存储链式存储
顺序栈链栈
队列循环队列链队列

主要考顺序存储,并且栈/队列单独只出现在选择题,在考研大题中都是作为一个工具来解决其他问题的,可以直接用数组表示,而不需要写各种函数。

一.栈 (stack)

栈顶(Top)进行插入/删除的一端。(只需定义栈顶即可)
栈底(Bottom)固定的一端,不进行操作。
空栈没有元素的空表。
操作特性后进先出(LIFO)

n个不同的元素顺序进栈,其出栈的不同排列的个数:
1 n + 1 C 2 n   n \color{cyan}\frac{1}{n+1}C_{2n}^{\ n} n+11C2n n在这里插入图片描述


1.顺序栈 (SqStack)

//简单定义加初始化
int data[Maxsize];
int top=-1;

格式化书写:

typedef struct{
	int data[Maxsize];
	int top;
}SqStack;

注:top指向栈顶元素
初始时,S.top = -1;
栈顶元素:S.data[S.top]
入栈:S.data[++S.top] = x;,出栈:x = S.data[S.top--];
栈空:S.top == -1,栈满:S.top == Maxsize-1

共享栈:

int data[Maxsize];
int top1 = -1 , top2 = Maxsize;

更有效地利用空间。

2.链栈 (LiSack)

带头结点/不带头结点均可。

bool push(LiStack &S);   入栈
bool pop(LiStack &S,int &x)

链头入栈:头插法

如果写函数,入栈/出栈记得传引用!
链栈出栈:判断是否为空

统考真题:
栈的统考真题都时考栈的顺序进栈,的出栈情况
一般情况下手写遍历一下就可以, 1 n + 1 C 2 n n \frac{1}{n+1}C_{2n}^n n+11C2nn一般用不上
递归 → \rightarrow 非递归,不一定要栈,比如斐波那契数列直接循环就行了


二.队列 (Queue)

队头(Front)进行删除的一端
队尾(Rear)进行插入的一端
空队没有元素的空表
操作特性先进先出FIFO

1.循环队列

单纯的顺序队列,有时虽然rear已经到数组尾了,但是因为队头front的不断前进,导致后面有很多空间空了出来不能被利用,这就导致了假溢出
为了充分利用数组空间,我们使用循环队列。
front:指向队头元素
rear:指向队尾元素的下一个位置

在这里插入图片描述
初始时:Q.front = Q.rear = 0;
入队:Q.rear = (Q.rear + 1) % Maxsize;
出队:Q.front = (Q.front + 1) % Maxsize;


为了区分队空/队满,有以下三种常用方法:(主要第一个)
1.牺牲一个单元,Q.rear 所指的块永远为空
队空:Q.front == Q.rear
队满:(Q.rear + 1)%Maxsize == Q.front
元素个数:(Q.rear-Q.front+Maxsize)%Maxsize;

在这里插入图片描述

2.加一个表示元素个数的数据成员 Q.size
队空:Q.size == 0
队满:Q.size == Maxsize

3.加一个 tag 数据成员,区分队空、队满
入队:Q.tag = 1
出队:Q.tag = 0
Q.front == Q.rear 时,若Q.tag == 0 ,则队空。若Q.tag == 1,则队满。

2.链队列

就是同时带头指针 front 和 尾指针 rear 的单链表

typedef struct LinkNode{
	int data;
	LinkNode* next;     //结点
}LinkNode;

typedef struct{
	LinkNode *front,*rear;  //仅保存头尾指针
}LinkQueue;

假设带头结点:
队空:Q.front == Q.rear

出队:判断是否为空、最后一个结点

bool Dequeue(Linkqueue& Q, int &x) {
	if (Q.rear == Q.front)
		return false;
	Linknode* p = Q.front->next;
	x = p->data;
	Q.front->next = p->next;
	if (p == Q.rear)        //如果就一个结点,rear指向front的结点,置空
		Q.rear = Q.front;
	delete(p);
	return true;
}

3.双端队列

输入受限的双端队列
输出受限的双端队列
在这里插入图片描述

统考真题:
大多是顺序存储的,循环队列,双端队列,19年考了一个链式队列

三.栈和队列的应用

括号匹配
表达式求值(后缀表达式)
递归
迷宫求解
队列层次遍历
缓冲区
页面替换算法
广度优先搜索图

1.括号匹配:
(1)左括号压栈,遇到右括号即取栈顶判断,若匹配则继续,若不匹配则匹配失败。
(2)若括号全部计算完后,栈内有剩余,则匹配失败。

2.表达式求值:
先用运算符栈,由中缀表达式得到后缀表达式,然后用数字栈得到计算结果。

中缀表达式 → \rightarrow 后缀表达式 (符号栈)

1.手写法
将所有操作用括号括起来,然后将操作符挪到括号后面,然后去掉括号。
a*(b+c)-d → \rightarrow ((a*(b+c))-d) → \rightarrow ((a(bc)+)*d)- → \rightarrow abc+*d-

2.栈方法:

  1. 运算数,直接输出。
  2. 运算符(括号除外),压栈时判断,将栈内优先级 ≥ \ge 自己的全部弹出输出(有就左括号停止)。
  3. 对于左右括号 () ,左括号直接压栈。遇到右括号,向下一直弹栈,直到弹出左括号为止。括号不输出。
  4. 若操作数没有了,则全部弹栈

a*(b+c)-d

输出运算符栈
a
a** 压栈
a(
*
( 压栈
ab+
(
*
+ 压栈
abc+
(
*
输出c
abc+*) 出现,弹栈,直到弹出 (
abc+*-* ≥ \ge -,* 弹栈
abc+*d-d输出
abc+*d--弹栈

后缀表达式 → \rightarrow 结果 (数字栈)

从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号(op),就将处于栈顶两个数字出栈(a,b),进行运算(b op a),运算结果进栈,一直到最终获得结果。

a*(b+c)-d
abc+*d-

比如 123+*4- = 1*(2+3)-4 = 1

操作数栈符号
3
2
1
数字压栈
12 + 3+,弹出3,2,计算2+3
5
1
得到结果5,压栈
1 * 5*,弹出5,1,计算1*5
5得到结果5,压栈
4
5
数字压栈
5 - 4-,弹出4,5,计算5-4
1结果

3.递归
(1).递归调用时,系统会为每一层递归函数的返回点,局部变量,传入参数等开辟递归工作栈来存储数据。
(2).递归次数过多容易造成栈溢出。
(3).递归的优点是可以用很精简的代码解决问题,但是递归效率低,因为包含了很多的重复计算。(分治法一般都是)
(4).递归的应用:
阶乘问题、二叉树深度、汉诺塔问题、斐波那契数列、快速排序、归并排序(分治算法体现递归)、遍历文件,解析xml文件

(5).解决递归问题一般就三步曲,分别是:
第一步,定义函数功能
第二步,寻找递归终止条件
第二步,递推函数的等价关系式

4.二叉树层次遍历:
(1).根入队
(2).若队空,结束遍历
(3).队中第一个结点出队,若其有左孩子,左孩子入队,若有右孩子,右孩子入队。

统考真题:
中缀转后缀表达式的栈方法,一定要掌握!考了两次
函数的栈存储考了一次
缓冲区队列一次
内容不多…

四.特殊矩阵的压缩存储

在这里插入图片描述
注:矩阵是[1…n][1…n],首先看按行/列优先存取,其次存到一维数组B[0…k-1],其坐标从0开始!所以计算后要 -1!

1.对称矩阵

a i j = a j i a_{ij}=a_{ji} aij=aji,我们只需要存储:上/下三角+对角线即可
A [ 1.. n ] [ 1.. n ] → B [ n ( n + 1 ) 2 ] A[1..n][1..n]\rightarrow B[\frac{n(n+1)}{2}] A[1..n][1..n]B[2n(n+1)],若存储下三角矩阵,按行存储,则 a i j = ( 1 + 2 + . . . + i − 1 + j ) − 1 = B [ i ( i − 1 ) 2 + j − 1 ] a_{ij}=(1+2+...+i-1+j)-1=B[\frac{i(i-1)}{2}+j-1] aij=(1+2+...+i1+j)1=B[2i(i1)+j1]上三角的元素在B中为: B [ j ( j − 1 ) 2 + i − 1 ] B[\frac{j(j-1)}{2}+i-1] B[2j(j1)+i1]

2.三角矩阵

即上/下三角部分为常数,我们只需要存储非常数的三角+对角线+常数
A [ 1.. n ] [ 1.. n ] → B [ n ( n + 1 ) 2 + 1 ] A[1..n][1..n]\rightarrow B[\frac{n(n+1)}{2}+1] A[1..n][1..n]B[2n(n+1)+1]

3.三对角矩阵

在这里插入图片描述
三对角矩阵,即只有以主对角线为中心的三个对角线上元素非0,其他地方元素都是0。
第一行,第n行都只有2个元素,其他行都有3个元素, a i i a_{ii} aii为第i行第2个。
a i j = 2 + 3 ∗ ( i − 2 ) + ( j − i + 2 ) − 1 = B [ 2 i + j − 3 ] a_{ij}=2+3*(i-2)+(j-i+2)-1=B[2i+j-3] aij=2+3(i2)+(ji+2)1=B[2i+j3]

4.稀疏矩阵

非0元极少,大多数都是0
我们可以只存储非0元的 行、列、数值
三元组、十字链表法均可以完成。
在这里插入图片描述

统考真题,统一格式:
1.给定一个特殊矩阵
2.说明按行/列,存入一维数组
3. a i j a_{ij} aij在数组中的下标!
坑点:
看清楚按行/列存储,20年突然写个按列存储…
求的是下标!矩阵都是(1,1)开始,所以最后要记得 − 1 -1 1
考过了,对称矩阵,三对角矩阵,稀疏矩阵,不知道下一次会考什么矩阵…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值