开发环境
windows 10
visual studio 2019
c
1 栈
仅一头进出
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXSIZE 50 //定义栈中元素的最大个数
#define true 1
#define false 0
typedef int ElemType; //定义栈的元素类型
1.0 瞎写
- 对于 n n n个不同元素进栈,出栈序列的个数为 1 n + 1 C 2 n n \frac{1}{n+1}C^n_{2n} n+11C2nn【卡特兰数】
1.1 顺序栈
typedef struct {
ElemType data[MAXSIZE]; //存放栈中元素
int top; //栈顶指针
}SqStack;
void InitStack(SqStack S);
_Bool StackEmpty(SqStack S);
_Bool Push(SqStack S, ElemType x);
_Bool Pop(SqStack S, ElemType x);
_Bool GetTop(SqStack S, ElemType x);
_Bool DestroyStack(SqStack* S);
1.1.1 栈初始化
初始化一个空栈S。
void InitStack(SqStack S) {
S.top = -1; //初始化栈顶指针
}
如果初始化S.top=0的话,进栈操作就是S.top++而不是++S.top(知道的吧,嗯)。联系我忘得差不多了的汇编知识,最好是先+1,再存。
1.1.2 判空操作
判断一个栈是否为空,若栈S为空则返回true,否则返回false。
_Bool StackEmpty(SqStack S) {
if (S.top == -1)
return true; //栈空
else
return false; //不空
}
1.1.3 进栈
进栈,若栈S未满,则将x加入使之成为新栈顶。
_Bool Push(SqStack S, ElemType x) {
if (S.top == MAXSIZE - 1) //栈满,报错
return false;
S.data[++S.top] = x; //指针先+1,再入栈
return true;
}
1.1.4 出栈
出栈,若栈S非空,则弹出栈顶元素,并用x返回。
_Bool Pop(SqStack S, ElemType x) {
if (S.top == -1) //栈空,报错
return false;
x = S.data[S.top--]; //先出栈,指针再-1
return true;
}
1.1.5 读栈顶元素
读栈顶元素,若栈S非空,则用x返回栈顶元素。
_Bool GetTop(SqStack S, ElemType x) {
if (S.top == -1) //栈空,报错
return false;
x = S.data[S.top]; //x记录栈顶元素
return true;
}
1.1.6 销毁栈
销毁栈,并释放S占用的存储空间。
_Bool DestroyStack(SqStack* S) {
if (!S)
return false;
free(S);
return true;
}
1.2 链栈
typedef struct Linknode {
ElemType data; //数据域
struct Linknode* next; //指针域
}* LiStack; //栈类型定义
出栈、入栈都在头结点那操作
1.2.1 入栈
假如入栈s
s->next = L->next;
L->next = s;
1.2.2 出栈
假如出栈栈顶元素s
s = L->next;
L->next = s->next;
free(s);
2 队列
仅一头进,另一头出
#define MAXSIZE 50 //定义队列中元素的最大个数
#define true 1
#define false 0
typedef int ElemType; //定义队列的元素类型
typedef struct {
ElemType data[MAXSIZE]; //存放队列元素
int front, rear; //队头指针和队尾指针
}SqQueue;
void InitQueue(SqQueue Q); //初始化队列,构造一个空队列Q
_Bool QueueEmpty(SqQueue Q); //判队列空,若队列Q为空返回true,否则返回false
void EnQueue(SqQueue Q,ElemType x); //入队,若队列Q未满,将x加入,使之成为新的队尾
_Bool DeQueue(SqQueue Q, ElemType x); //出队,若队列Q非空,删除队头元素,并用x返回
_Bool GetHead(SqQueue Q, ElemType x); //读队头元素,若队列Q非空,则将队头元素赋值给x
2.1 队列基操
2.1.1 初始化(队空条件)
Q.front == Q.rear == 0;
2.1.2 进队
元素s进队
data[Q.rear++] = s;
2.1.3 出队
队头元素s出队
s = data[Q.front++];
2.2 循环队列
圈成圈
2.2.0 区分队空和队满的其他方式
方式1:增设表示元素个数的数据成员size
Q.size == 0; //队空
Q.size == MAXSIZE; //队满
方式2:增设判断队列是否已满的数据成员tag
tag = 0时,因删除导致 Q.rear == Q.front; //队空
tag = 1时,因插入导致 Q.rear == Q.front; //队满
方式3:牺牲一个单元来区分队空和队满,入队时少用一个队列单元
2.2.1 队空条件
Q.front == Q.rear == 0;
2.2.2 队满条件
(Q.rear + 1) % MAXSIZE == Q.front;
2.2.3 队列长度
(Q.rear + MAXSIZE - Q.front) % MAXSIZE;
2.2.3 进队
data[Q.rear] = s;
Q.rear = (Q.rear + 1) % MAXSIZE;
2.2.4 出队
s = data[Q.front];
Q.front = (Q.front + 1) % MAXSIZE;
2.2 链队列
带头结点的单链表。
void InitQueue(LinkNQueue Q);
_Bool QueueEmpty(LinkNQueue Q);
void EnQueue(LinkNQueue Q,ElemType x);
_Bool DeQueue(LinkNQueue Q, ElemType x);
_Bool GetHead(LinkNQueue Q, ElemType x);
typedef struct { //链式队列结点
ElemType data;
struct LinkNode* next;
}LinkNode;
typedef struct { //链式队列
LinkNode* front, * rear; //队列的队头和队尾指针
}LinkNQueue;
2.2.1 队列初始化
void InitQueue(LinkNQueue Q) {
Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode)); //建立头结点
Q.front->next = NULL; //初始为空
}
2.2.2 判队空
_Bool QueueEmpty(LinkNQueue Q) {
if (Q.front == Q.rear)
return true;
return false;
}
2.2.3 入队
void EnQueue(LinkNQueue Q, ElemType x) {
LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
/*创建新结点,插入到链尾*/
s->data = x;
s->next = NULL;
Q.rear->next = s;
Q.rear = s;
}
2.2.4 出队
_Bool DeQueue(LinkNQueue Q, ElemType x) {
if (QueueEmpty(Q))
return false; //空队
LinkNode* s = Q.front->next; //跳过头结点
x = s->data;
Q.front->next = s->next;
if (Q.rear == s)
Q.rear = Q.front; //若原队列中只有一个结点,删除后边空
free(s);
return true;
}
2.2.5 读取队头元素值
_Bool GetHead(LinkNQueue Q, ElemType x) {
if (QueueEmpty(Q))
return false; //空队
LinkNode* s = Q.front->next; //跳过头结点
x = s->data;
return true;
}
2.3 双端队列
两头都可以进行入队和出队。
2.3.1 输出受限的双端队列
允许在一头进行入队和出队,另一头只允许入队的双端队列。
2.3.2 输入受限的双端队列
允许在一头进行入队和出队,另一头只允许出队的双端队列。
3 栈和队列的应用
3.1 栈的应用
(1)括号匹配
(2)表达式求值——后缀表达式(逆波兰表示法)
(3)递归→非递归:
递归:在一个函数、过程或数据结构的定义中又应用了它自身
递归模型不能是循环定义的,必须满足2个条件:
<1> 递归表达式(递归体)
<2> 边界条件(递归出口)
3.2 队列的应用
(1)层次遍历【保存下一步的处理顺序】
(2)在计算机系统中的应用
<1> 解决主机与外部设备之间速度不匹配的问题
<2> 解决由多用户引起的资源竞争问题
4 特殊矩阵的压缩存储
4.1 数组的存储结构
二维数组 a[weight][height]
size:元素存储单元
4.1.1 先行后列
L O C ( a i , j ) = L O C ( a 0 , 0 ) + [ r o w × ( h e i g h t + 1 ) + c o l ] × s i z e LOC(a_{i,j})=LOC(a_{0,0})+[row×(height+1)+col]×size LOC(ai,j)=LOC(a0,0)+[row×(height+1)+col]×size
4.1.2 先列后行
L O C ( a i , j ) = L O C ( a 0 , 0 ) + [ c o l × ( w e i g h t + 1 ) + r o w ] × s i z e LOC(a_{i,j})=LOC(a_{0,0})+[col×(weight+1)+row]×size LOC(ai,j)=LOC(a0,0)+[col×(weight+1)+row]×size
4.2 矩阵的压缩存储
4.2.1 对称矩阵
4.2.2 三角矩阵
4.2.3 三对角矩阵
4.3 稀疏矩阵
5 参考
王道,侵删