栈与队列
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.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;elsereturn 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加1return 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 10typedef 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;elsereturn false;}
//不带头结点void InitQueue(LinkQueue &Q){Q.front=NULL;Q.rear=NULL;}//判空bool IsEmpty(LinkQueue Q){if (Q.front==NULL)return true;elsereturn 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
(2)三角矩阵:
(3)三对角矩阵:带状矩阵;当|i-j|>1,有Ai,j=0
(4)稀疏矩阵:非零元素远远小于矩阵元素个数:顺序存储(<行,列,值>)
十字链表法
