文章目录
第三章 栈,队列和数组
3.1 栈
3.1.1 栈的基本概念
1.栈的定义
栈是只允许在一端进行插入或删除操作的线性表。首先栈是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作。
栈顶:允许进行插入删除的那一端
栈底:固定的,不允许进行插入和删除操作的另一端
空栈:不含任何元素的空表。
栈的操作特性是:先进后出。
2.栈的基本操作
名称 | 详解 |
---|---|
InitStack(&S) | 初始化一个空栈 |
StacEmpty(S) | 判断是否为空,若为空则返回true,否则返回false |
Push(&S,X) | 进栈 |
Pop(&S,&X) | 出栈 |
GetTop(S,&x) | 读取栈顶元素 |
DestroyStack(&S) | 销毁栈,并释放栈S占用的存储空间 |
3.1.2 栈的基本存储结构
栈是一种受限制的线性表,类似于线性表。
1.顺序栈的实现
采用顺序存储的方式进行存储,top指针放在栈顶的位置。
当对栈的的最大使用空间不足时,会发生栈上溢的情况。
栈空条件:S.top == -1,栈满条件:S.top == MaxSize -1 栈长:S.top + 1;
2.顺序栈的基本运算
(1)初始化
void InitStack(SqStack &S){
S.top = -1; //初始化栈顶指针
}
(2)栈判空
bool StackEmpty(SqStack S){
if(S.top == -1){
return true; //栈空
}
else
return false; //不空
}
(3)进栈
bool Push(SqStack &S,ElemType e){
if(S.top == Maxsize - 1){ //如果栈满的话就会报错
rerurn false;
}
S.data[++S.top] = X; //指针先加1,再入栈
return ture;
}
(4)出栈
bool Pop(SqStack &S,ElemType &x){
if(S.top == -1){ //栈空,则会报错
return false;
}
X = S.data[S.top--]; //先出栈,指针再减1
return rute;
}
(5)读取栈顶元素
bool GetTop(SqStack S,ElemType &X){
if(S.top == -1){ //栈空则报错
return false;
}
X = S.data[S.top]; //记录栈顶元素
return ture;
}
3.共享栈
共享栈是为了更有效的利用存储空间,两个栈的空间相互调节。只有在整个存储空间被占满时才发生上溢。
3.1.3 栈的链式存储结构
采用链式存储的栈称为链栈。链栈的优点就是多个栈共享存储空间和提高其效率,不存在栈上溢的情况。
3.1.3
3.2 队列
3.2.1 队列的基本概念
1.队列的定义
只下允许在表的一端进行插入,在表的另一端进行删除,插入操作称为入队或进队,删除操作称为出队或离队。
特性:先进先出
队首:允许删除的一端。
队尾:允许插入的一端。
空队列。不含任何元素的空表。
2.队列常见的基本操作
名称 | 详解 |
---|---|
InitQueue(&Q) | 初始化队列,构造一个空队列Q |
QueueEmpty(Q) | 判空:true:false |
EnQueue(&Q,x) | 入队 |
DeQueue(&Q,&x) | 出队 |
GetHead(Q,&x) | 读取队头 |
3.2.2 队列的顺序存储结构
1.队列的顺序存储
初始化,栈空条件:Q.front == Q.rear == 0;
先进先出,后进后出
进栈操作:队不满时,先送值到队尾元素,再将队尾指针加1
出栈操作:栈不空时,先取队头元素,再将队头指针加1;
2.循环队列
循环队列相当于一个环状的空间,存储的逻辑上是一个环,称为循环队列,
3.循环队列的操作
初始化:Q.front = Q.rear = 0;
队首指针进1:Q.front = (Q.front + 1) % MaxSize;
队尾指针进1:Q.rear = (Q.rear + 1) % MaxSize;
队列长度:(Q.rear + MaxSize - Q.front)%MaxSize;
出队和入队时,指针都被顺时针方向进1;
判断空的条件:Q.front = Q.rear;
判断队满的条件::Q.front = Q.rear;
由于队空和队满的条件是相同的,因此有一下三种方式进行处理:
(1)牺牲一个单元来区分队空和队满,入队时少用一个队列单元,这是一种比较普遍的做法。
队满条件:(Q.rear + 1) % MaxSize == Q.front;
队空条件:Q.front = Q.rear;
队列中存储元素的个数:(Q.rear - Q.front + MaxSize) % MaxSize;
(2)类型中增设表示元素个数的数据成员:这样的话队空的条件就是Q.Size == 0;
队满的情况就是:Q.Size ==MxSize;,这两种情况都有Q.front == Q.rear;
(3)类型中增设tag数据成员,以区分是队满还是队空。tag等于0时,若因删除导致Q.front == Q.rear,则为队空,若因插入Q.front ==Q.rear,则为队满。
3.循环队列的操作
(1)初始化
void InitQueue(SqQueue &Q){
Q.rear = Q.front = 0;
}
(2)判空
bool isEmpty(SqQueue Q){
if(Q.front = Q.rear;){
return ture;
}
else{
return false;
}
}
(3)入队
bool EnQueue(SqQueue &Q,ElemType x){
if((Q.rear + 1) % MaxSize == Q.front){
return false;
}
Q.data[Q.rear] = x;
Q.rear = (Q.rear + 1 ) % MaxSize;
return true;
}
(4)出队
bool DeQueue(SqQueue &Q,ElemType x){
if(Q.rear == Q.front){
return false;
}
X = data[Q.front];
Q.front = (Q.front + 1) % MaxSize;
return true;
}
3.2.3 队列的链式存储结构
1.队列的链式存储(带有头节点的)
当Q.front == NULL且Q.rear == NULL时,链式队列为空。
若程序中需要使用多个队列,最好使用链式队列,这样就不会出现存储分配不合理和“溢出”的问题。
链式存储不存在栈满的情况
(1)初始化
void InitQueue(LinkQueue &e){
Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
Q.front -> NULL;
}
(2)判队空
bool isEmpty(LinkQueue Q){
if(Q.rear == Q.front){
return falase;
}
else{
rerurn true;
}
}
(3)入队
void EnQueue(LinkQueue &Q,EmemType x){
LinkNode *S = (LinkNode *)malloc(sizeof(LinkNode)); //初始化
s -> data = x;
s -> next = NULL; //创建新的结点,插入到队尾。
Q.rear -> next = s;
Q.rear = s;
}
(4)出队
bool DeQueue(LinkQueue &Q,ElemType &x){
if(Q.rear == Q.front){
return false;
}
LinkNode *p = Q.front -> next; //P指向队首
x = p -> date;
Q.front -> next = p -> next;
if(Q.rear == p){
Q.rear == Q.front; //若原队列中只有一个结点,删除后变空
}
free(p);
return true;
}
3.2.4 双端队列
双端队列是指允许两端都可以进入队和出栈操作的队列/
输出受限的双端队列:允许在一端进行插入和删除,但是在另一端只允许插入的双端队列称为输出受限的双端队列。
输入受限的双端队列:允许在一端进行插入和删除,但是在另一端只允许删除的双端队列称为输入受限的双端队列。
输入是入队,输出是出队。
在栈中合法的输出序列,在双端队列中必定合法。
3.2.5
3.3 栈和队列的应用
3.3.1 栈在括号匹配中的应用
就是括号的匹配问题
3.3.2 栈在表达式求值中的应用
。。。。。。
3.3.3 栈在递归中的应用
递归的次数过多的话容易造成栈的溢出,效率不高的原因是递归调用中包含很多重复的计算。
3.3.4 队列在层次遍历中的应用
应用:二叉树
3.3.5 队列在计算机系统中的应用
应用:缓冲区
3.3.6
3.4 数组和特殊矩阵
3.4.1 数组的定义
数组是由n个相同类型的数据元素构成的有限序列,每个数据称为一个数据元组。
除了结构的初始化和销毁外,数组只会有存储元素和修改元素的操作。
3.4.2 数组的存储结构
对于多维数组,有两种映射方式,按行优先和按列优先,二维数组就是按行优先。
3.4.3 特殊矩阵的压缩存储
1.对称矩阵
对称矩阵存放在一堆数组中[ n ( n + 1 ) / 2 ]:
2.三角矩阵
下三角矩阵压缩存储在[ n ( n + 1 ) / 2 + 1 ];(其中的1是常量的存储)
3.三对角矩阵
对角矩阵又称为带状矩阵。
3.4.4 稀疏矩阵
稀疏矩阵:非零元素远远小于矩阵的个数。
压缩存储策略:三元组存储(每个三元组含有行,列,元素值)
压缩策略二:十字链表法