1.栈(Stack)
栈是只允许在一端进行插入或删除操作的线性表
特点:后进先出(Last In First Out )LIFO
基本操作:
InitStack(&S):初始化栈,构造一个空栈S,分配内存空间。
DestroyStack(&L):销毁栈,销毁并释放S所占用的内存空间。
Push(&S,x):进栈,若栈S未满,则将x加入使之成为新栈顶。
Pop(&S,&x):出栈,若栈S非空,则弹出栈顶元素,并用x返回。
GetTop(S,&x):读栈顶元素,若栈S非空,则用x返回栈顶元素。
................
2.栈的顺序存储
//顺序栈的定义
#define MaxSize 10 //定义栈中元素的最大个数
typedef struct{
ElemType data[MaxSize];//静态数组存放栈中元素
int top; //栈顶指针
}SqStack;
//初始化
void InitStack(SqStack &S){
S.top=-1; //初始化栈顶指针
}
//判断栈空
bool isEmpty(SqStack S){
return S.top == -1;
}
//入栈
bool Push(SqStack &S,ElemType x){
if(S.top == MaxSize-1) //栈满
return false;
S.top=S.top+1; //指针+1
S.data[S.top] = x; //入栈
return true;
}
//出栈
bool Pop(SqStack &S,ElemType &x){
if(S.top == -1) //栈空
return false;
x=S.data[S.top]; //栈顶元素出栈
S.top=S.top-1; //指针-1
return true;
}
//读栈顶元素
bool GetTop(SqStack S,ElemType &x){
if(S.top == -1)
return false;
x=S.data[S.top];
return true;
}
int main(){
SqStack S;//声明一个顺序栈(分配空间)
}
综合案例:
#include<stdio.h>
#define MaxSize 10 //定义栈中元素的最大个数
typedef struct{
int data[MaxSize];//静态数组存放栈中元素
int top; //栈顶指针
}SqStack;
//初始化
void InitStack(SqStack &S){
S.top=-1; //初始化栈顶指针
}
//判断栈空
bool isEmpty(SqStack S){
return S.top == -1;
}
//入栈
bool Push(SqStack &S,int x){
if(S.top == MaxSize-1) //栈满
return false;
S.top=S.top+1; //指针+1
S.data[S.top] = x; //入栈
return true;
}
//出栈
bool Pop(SqStack &S,int &x){
if(S.top == -1) //栈空
return false;
x=S.data[S.top]; //栈顶元素出栈
S.top=S.top-1; //指针-1
return true;
}
//读栈顶元素
bool GetTop(SqStack S,int &x){
if(S.top == -1)
return false;
x=S.data[S.top];
return true;
}
int main(){
SqStack S;//声明一个顺序栈(分配空间)
InitStack(S);
printf("push:");
if(isEmpty(S)){
Push(S,20);//入栈
Push(S,21);
Push(S,22);
Push(S,23);
Push(S,24);
Push(S,25);
Push(S,26);
Push(S,27);
Push(S,28);
Push(S,29);
}
Push(S,30);//此时栈满,不再存入数据
//打印数据
for(int i=0;i<=S.top;i++){
printf("%d\t",S.data[i]);
}
//出栈
printf("\npop:\n");
int x;
Pop(S,x);
printf("%d\n",x);
Pop(S,x);
printf("%d\n",x);
Pop(S,x);
printf("%d\n",x);
Pop(S,x);
printf("%d\n",x);
//获取栈顶元素
int y;
GetTop(S,y);
printf("top number:%d",y);
}
结果:
push:20 21 22 23 24 25 26 27 28 29
pop:
29
28
27
26
top number:25
--------------------------------
共享栈:(栈满:top0+1==top1)
//共享栈
#define MaxSize 10 //定义栈中元素的最大个数
typedef struct{
ElemType data[MaxSize];//静态数组存放栈中元素
int top0; //栈顶指针
int top1;
}ShStack;
//初始化
void InitStack(ShStack &S){
S.top0=-1; //初始化栈顶指针
S.top1=MaxSize;
}
3.栈的链式存储
//栈的链式存储
//定义 (只能在表头的位置进行插入和删除)
typedef struct LinkNode{
ElemType data; //数据域
struct LinkNode *next; //指针域
}*LiStack;
综合案例:
//栈的链式存储
//定义 (只能在表头的位置进行插入和删除)
#include<stdio.h>
#include<malloc.h>
typedef struct LinkNode{
int data; //数据域
struct LinkNode *next; //指针域
}*LiStack;
void InitStack(LiStack &S){
S=(LinkNode*)malloc(sizeof(LinkNode));
S->next=NULL;
}
bool Insert(LiStack S,int x){
LinkNode *p;
p=(LinkNode*)malloc(sizeof(LinkNode));
p->data=x;
p->next=S->next;
S->next=p;
return true;
}
bool isEmpty(LiStack S){
return S->next==NULL;
}
bool Delete(LiStack S,int &x){
LinkNode *q;
q=S->next;
x=q->data;
S->next=q->next;
free(q);
return true;
}
int main(){
LiStack S;
InitStack(S);
if(isEmpty(S)){
Insert(S,30);
Insert(S,31);
Insert(S,32);
Insert(S,33);
Insert(S,34);
Insert(S,35);
}
LiStack p=S->next;
while(p!=NULL){
printf("%d\t",p->data);
p=p->next;
}
printf("\n");
int x;
Delete(S,x);
printf("delete num: %d\n",x);
Delete(S,x);
printf("delete num: %d\n",x);
Delete(S,x);
printf("delete num: %d\n",x);
}
结果:
35 34 33 32 31 30
delete num: 35
delete num: 34
delete num: 33
4.队列(Queue)
队列是只允许在一端进行插入,在另一端删除的线性表
队尾:允许插入的一端
队头:允许删除的一端
特点:先进先出(First In First Out)FIFO
基本操作:
InitQueue(&Q):初始化队列,构造一个空队列。
DestroyQueue(&Q):销毁队列,销毁并释放队列所占用的内存空间。
EnQueue(&Q,x):入队,若队列Q未满,则将x加入使之成为新队尾。
DeQueue(&Q,&x):出队,若队列Q非空,则删除队头元素,并用x返回。
GetHead(Q,&x):读队头元素,若队列Q非空,则将队头元素赋值给x。
................
5.队列的顺序存储
//队列的顺序存储
#define MaxSize 10
typedef struct{
ElemType data[MaxSize]; //静态数组存放队列元素
int front,rear; //队头和队尾指针
}SqQueue;
//初始化队列
void InitQueue(SqQueue &Q){
Q.front=Q.front=0;
}
//判断是否为空
bool QueueEmpty(SqQueue Q){
return Q.front==Q.rear;
}
//入队
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;
}
//出队
bool DeQueue(SqQueue &Q,ElemType &x){
if(Q.rear == Q.front)
return false;
x=Q.data[Q.front];
Q.front=(Q.front+1)%MaxSize;
return true;
}
//获得队头元素的值
bool GetHead(SqQueue Q,ElemType &x){
if(Q.rear == Q.front)
return false;
x=Q.data[Q.front];
return true;
}
//队列元素的个数:(rear+MaxSize-front)% MaxSize
int main(){
SqQueue Q;
InitQueue(Q);
}
综合案例:
//队列的顺序存储
#include<stdio.h>
#define MaxSize 10
typedef struct{
int data[MaxSize]; //静态数组存放队列元素
int front,rear; //队头和队尾指针
}SqQueue;
//初始化队列
void InitQueue(SqQueue &Q){
Q.front=Q.front=0;
}
//判断是否为空
bool QueueEmpty(SqQueue Q){
return Q.front==Q.rear;
}
//入队
bool EnQueue(SqQueue &Q,int x){
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 GetHead(SqQueue Q,int &x){
if(Q.rear == Q.front)
return false;
x=Q.data[Q.front];
return true;
}
int main(){
SqQueue Q;
InitQueue(Q);
if(QueueEmpty(Q)){
EnQueue(Q,15);
EnQueue(Q,16);
EnQueue(Q,17);
EnQueue(Q,18);
EnQueue(Q,19);
EnQueue(Q,20);
EnQueue(Q,21);
}
int x;
DeQueue(Q,x);
printf("delete:%d\n",x);
DeQueue(Q,x);
printf("delete:%d\n",x);
int y;
GetHead(Q,y);
printf("head number:%d",y);
}
结果:
delete:15
delete:16
head number:17
6.队列的链式存储
//队列的链式存储
#include<stdio.h>
#include<malloc.h>
typedef struct LinkNode{
ElemType 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;
}
//初始化(不带头节点)
void InitQueue(LinkQueue &Q){
Q.front=Q.rear=NULL;
}
//入队(带头节点)
void EnQueue(LinkQueue &Q,ElemType x){
LinkNode *s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=x;
s->next=NULL;
Q.rear->next=s;
Q.rear=s;
}
//入队(不带头节点)
void EnQueue(LinkQueue &Q,ElemType 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;
}
}
//出队(带头节点)
void DeQueue(LinkQueue &Q,ElemType &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.front=Q.rear;
}
free(p);
return true;
}
//出队(不带头节点)
void DeQueue(LinkQueue &Q,ElemType &x){
if(Q.front==NULL)
return false;
LinkNode *p=Q.front;
x=p->data;
Q.front=p->next;
if(Q.rear == p){
Q.front=NULL;
Q.rear=NULL;
}
free(p);
return true;
}
//判断是否为空
bool isEmpty(LinkQueue Q){
return Q.front == Q.rear;
}
int main(){
LinkQueue Q;
InitQueue(Q);
}
综合案例:
//队列的链式存储
#include<stdio.h>
#include<malloc.h>
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;
}
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;
}
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.front=Q.rear;
}
free(p);
return true;
}
bool isEmpty(LinkQueue Q){
return Q.front == Q.rear;
}
int main(){
LinkQueue Q;
InitQueue(Q);
if(isEmpty(Q)){
EnQueue(Q,13);
EnQueue(Q,14);
EnQueue(Q,15);
EnQueue(Q,16);
EnQueue(Q,17);
EnQueue(Q,18);
}
int x;
DeQueue(Q,x);
printf("del:%d\n",x);
DeQueue(Q,x);
printf("del:%d\n",x);
}
结果:
del:13
del:14
7.双端队列
双端队列:只允许从两端插入、两端删除的线性表
输入受限的双端队列:只允许从一端插入、两端删除的线性表
输出受限的双端队列:只允许从两端插入、一端删除的线性表
8.栈的应用
括号匹配:
//栈的应用(括号匹配)
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 10
typedef struct{
char data[MaxSize];
int top;
}SqStack;
void InitStack(SqStack &S){
S.top=-1;
}
bool isEmpty(SqStack &S){
return S.top == -1;
}
bool Push(SqStack &S,char x){
if(S.top == MaxSize-1)
return false;
S.top++;
S.data[S.top]=x;
return true;
}
bool Pop(SqStack &S,char &x){
if(S.top == -1)
return false;
x=S.data[S.top];
S.top--;
return true;
}
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(isEmpty(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 isEmpty(S);
}
int main(){
char str[]="{(()[])}";
int len=8;
bool flag=bracketCheck(str,len);
printf("%d",flag); //打印结果:1
}
栈在表达式中求值:
Reverse Polish notation(逆波兰表达式=后缀表达式)
Polish notation(波兰表达式=前缀表达式)
中缀表达式:a+b (运算符在两个操作数中间)a+b-c a+b-c*d
后缀表达式:ab+(运算符在两个操作数后面)ab+c- /abc-+ ab+cd*-
前缀表达式:+ab(运算符在两个操作数前面) -+abc -+ab*cd
栈在递归中的应用:
最后被调用的函数最先执行结束(LIFO)
适合“递归”算法解决:可以把原始问题转换为属性相同,但规模较小的问题
9.队列的应用
树的层次遍历
图的广度优先遍历
多个进程争着使用有限的系统资源时,FCFS(First Come First Service,先来先服务)是一种常用策略
10.特殊矩阵的压缩存储