【数据结构】第2章 栈和队列

开发环境

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 参考

王道,侵删

猜你喜欢

转载自blog.csdn.net/qq_44714521/article/details/107006504