栈与队列
1.栈
线性表的一种,插入与删除只允许在一端进行操作
术语:栈顶,桟低,空栈
特点:后进先出(LIFO,Last in First Out)
进栈顺序:a->b->c->d->e
出栈顺序:后进先出
(1)所有元素都近栈后出栈:e->d->c->b->a;
(2)进栈出栈穿插:b->e->d->c->a;
总结:有N个元素入栈,则有卡特兰数
1
n
+
1
C
2
m
m
(
2
m
在
下
,
m
在
上
)
\frac{1}{n+1}C^m_2m(2m在下,m在上)
n+11C2mm(2m在下,m在上)
例如 3个元素入栈则有5种出栈情况
1.1顺序栈-栈的大小不可变
定义+初始化
#define MaxSize 10
//定义
typedef struct{
ElemType data[MaxSize];
int top0;
int top1;//共享栈指针
}SqStack;
//初始化
void InitStack(SqStack &S){
S.top0=-1;
S.top1=MaxSize;//共享栈指针在最上方,从最上方插入元素
}
判空操作
bool Elmpy(SqStack S){
if(S.top0==-1 && S.top1==MaxSize)
return true;
else
return false;
}//栈满的条件:S.top0+1==S.top1
进栈操作
bool Push(SqStack &S,ELempType i){
if(S.top==MaxSize-1)
return false;
S.top0=S.top0+1;
S.data[S.top0]=i;
//以上两步等价与S.data[++S.top0]=i;//注意++S.to0p与S.top0++不一样,前者是先加一后调用,后者先调用后top0加1
return true;
}
出栈操作
bool Pop(SqStack &S,int &x){
if (S.top0==-1)
return false;
x=S.data[S.top0];
S.top0=S.top0-1;//x=S.data[S.top0--];
}
读取栈顶元素
bool ReadTop(SqStack S,int &x){
if(S.top0==-1)
return false;
x=S.data[S.top0];
return true;
}
1.2 链栈(链式存储结构)
//定义
typedef struct LinkNode{
ElemType data;
struct LinkNode *next;
}*LiStack;
//其余详见单(双)链表
2.队列
只允许在一端插入,另一端进行删除操作。
特点:先进先出(FIFO:First In First Out)
术语:队头、队尾、空队列
计算元素个数:(rear+MaxSize-front)%MaxSize
2.1顺序存储
定义和初始化静态队列
#define MaxSize 10
typedef struct{
ElemType data[MaxSize];
int front,rear;//声明队头和队尾指针
}SqQueue;
void InitQueue(SqQueue &Q){
Q.rear=Q.front=0;//初始都指向0,Q为在main函数下声明的队列
}
入队操作
bool EnQueue(SqQueue &Q ,int e){
if ((Q.rear+1)%MaxSize==Q.front)//队尾指针的下个指针
return false;
Q.data[Q.rear]=x;
Q.rear=(Q.rear+1)%MaxSize;//亦可称为循环队列
return true;
}
出队操作
bool DeQueue(SqQueue &Q,int &x){
if (Q.rear==Q.front)//判断是否为空
return false;
x=Q.data[Q.front];
Q.front=(Q.front+1)%MaxSize;
return true;
}
#### 获取元素
bool GetQueue(SqQueue &Q,int &x){
if (Q.rear==Q.front)//判断是否为空
return false;
x=Q.data[Q.front];
return true;
}
2.2队列的链式存储
定义和初始化
//带头结点
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 IsEmpty(LinkQueue Q){
if (Q.front==Q.rear)
return true;
else
return false;
}
//不带头结点
void InitQueue(LinkQueue &Q){
Q.front=NULL;
Q.rear=NULL;
}
//判空
bool IsEmpty(LinkQueue Q){
if (Q.front==NULL)
return true;
else
return false;
}
入队操作
//带头结点
void EnQueue(LinkQueue &Q,int x){
LinkNode *s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=x;
s->next=NULL;
Q.rear->next=s;
Q.rear=s;
}
//不带头结点
void EnQueue(LinkQueue &Q,int x){
LinkNode *s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=x;
s->next=NULL;
if(Q.front==NULL){
Q.front=s;
Q.rear=s;
}
else{
Q.rear->next=s;
Q.rear=s;
}
}
出队操作
//带头结点
bool DeQueue(LinkQueue &Q ,int &x){
if (Q.front==Q.rear)
return false;
LinkNode *p=Q.front->next;
x=p->data;
Q.front->next=p->next;
if (Q.rear==p)
Q.rear=Q.front;
free(p);
return true;
}
//不带头结点
bool DeQueue(LinkQueue &Q ,int &x){
if (Q.front==NULL)
return false;
LinkNode *p=Q.front;
x=p->data;
Q.front->next=p->next;
if (Q.rear==p)
Q.rear=NULL;
Q.front=NULL;
free(p);
return true;
}
2.3双端队列
输入受限与输出受限的双端队列
3.栈与队列的应用
3.1栈在括号匹配中的应用
bool bracketCheck(char str[] ,int length){
SqStack S;
InitStack(S);//初始化栈
for(int i=0;i<length;i++){
if(str[i]=='('||str[i]=='['||str[i]=='{'){
Push(S,str[i]);}//左括号入栈
else{
if (StackEmpty(S))return false;//判断栈空
char topElem;
Pop(S,topElem);//栈顶元素出栈
if (str[i]==')'&&topElem!='(')return false;
if (str[i]==']'&&topElem!='[')return false;
if (str[i]=='}'&&topElem!='{')return false;
}
}
return StackEmpty(S);
}
3.2栈的表达式求值
1.三种算术表达式:中缀表达式、前缀表达式(波兰表达式)、后缀表达式(逆波兰表达式)(√)
中缀表达式:a+b,运算符在操作数中间;a+b-c;a+b-cd
后缀表达式:ab+,运算符在操作数后面;ab+c-/abc-+;ab+cd-
前缀表达式:+ab,运算符在操作数之前;-+abc/±bca;-+abcd
中缀转后缀【左优先原则:只要左边的运算符能先计算,就优先算左面的 】
中缀转前缀【右优先原则:只要右边的运算符能先计算,就优先算右面的】
中缀表达式求值:
(1)初始化两个栈。操作数栈,运算符栈
(2)扫描,按次序压入栈中,并按照左优先原则进行算数
3.3 栈在递归的调用
函数调用栈
3.4队列的应用
(1)树的层次遍历
(2)图的广度优先遍历
(3)在操作系统中进行FCFS(先来先服务)
3.5特殊矩阵的压缩存储
//一维数组
ElemType a[10];//各数组元素大小相同,物理上连续存放
//a[i]存放地址=loc+i*sizeof(ElemType);i从0开始
//二维数组
ElemType a[2][4];//两行四列;行优先与列优先
//b[i][j]存储地址=Loc+(i*N+j)*sizeof(ElemType)行优先(N为列)
//b[i][j]存储地址=Loc+(j*M+i)*sizeof(ElemType)列优先(M为行)
特殊矩阵:
(1)对称矩阵:若n阶方阵中对任意一个元素恒有Ai,j=Aj,i,则该矩阵为对称矩阵
主对角线i=j;上三角区;i<j;下三角区:i>j
(2)三角矩阵:
(3)三对角矩阵:带状矩阵;当|i-j|>1,有Ai,j=0
(4)稀疏矩阵:非零元素远远小于矩阵元素个数:顺序存储(<行,列,值>)
十字链表法