1.1栈和队列的特点和定义
栈:后进去先出来,最后插入的最先删除,是一种特殊的线性表只能从端点进行操作
队列:先进先出,最先进入队列的最先出来,只能插入在队列的末尾,只能删除表头的元素
1.2栈的应用
1.3队列的应用
注意:栈和队列是线性表的子集,是插入和删除受限的线性表
2.1栈的定义和特点
2.2栈的相关概念
2.3栈的示意图
3.1队列的定义和特点
3.2队列的特点
3.3队列的相关概念
4.1案例引入
案例4.2进制转换
在进制转换中,将10进制转换成8进制使用短除法获得十进制除以8的余数,将余数倒序排列就是8进制的表示,这时候采用栈的数据结构,先进后出,依次输出就是进制转换,方法同样适用于其他进制的转换当中。
案例4.3检验表达式中的括号是否匹配
在对于表达式中的括号进行匹配的时候,也是采用了栈的方式来进行检验,左括号先进栈,当发现右括号的时候和栈顶的左括号进行匹配,匹配成功将左括号进行出栈操作。先进栈的后匹配后进栈的先匹配,这样就完成了表达式中的括号匹配操作。
案例4.4表达式求值
算符优先级法来进行表达式的求值操作,具体操作还是比较复杂
案例4.5舞伴问题(队列)
这个案例是队列问题,先进先出。排在前面的人先进行舞伴的匹配,等一组队列全部出队,剩下一队列的进行下一轮的匹配。
5.1栈的表示和操作的实现
5.2栈的抽象数据类型的类型定义
基本操作
5.3顺序栈
顺序栈采用顺序表的形式,来创建栈的数据结构,通常为了方便top指针通常指向栈顶的下一个元素的地址,设置两个指针,栈顶指针top和栈底指针base以及一个表示最大容量的stacksize来表示栈,栈为空的条件是栈底指针和栈顶指针的地址相同。顺序栈表示方便但是容易造成溢出,上溢出被认为是错误,是问题的处理无法进行但是下溢出被认为是一种结束条件,表示问题的处理结束
5.4顺序栈的实现
5.5顺序栈的基本操作
算法1顺序栈的初始化
顺序栈的初始化,栈底指针指向动态内存分配的空间,判断是否分配成功,成功分配就让栈顶指针和栈底指针指向相同的地址来表示栈空。
算法2判断栈是否为空
算法3求顺序栈的长度
算法4清空顺序栈
算法5销毁顺序栈
算法6顺序表的入栈
算法7顺序栈的出栈
顺序栈代码实现
#include<stdilb.h>
#define maxsize 100
typedef int selemtype;
typedef struct{
selemtype *base;//栈底指针
selemtype *top;//栈顶指针
int stacksize;//栈的可用最大容量
}Sqstack;//顺序栈
Sqstack *s;
//顺序栈的初始化
int InitStack(Sqstack *s){
s->base=(selemtype*)malloc(sizeof(selemtype)*maxsize);//动态分配maxsize大小的空间
if(!s->base){
return 0; //存储分配失败
}
s->top=s->base; //栈顶指针等于栈底指针
s->stacksize=maxsize;
return 1;
}
//判断栈是否为空
int StackEmpty(Sqstack *s){ //若栈为空,返回1,否则返回0;
if(s->base==s->top){
return 1;
}
else{
return 0;
}
}
//求顺序栈的长度
itn Stacklength(Sqstack *s){
return (s->top-s->base);
}
//清空顺序栈
int Clearstack(Sqstack *s){
if(s->base){
s->top=s->base //如果顺序栈存在,将栈顶指针top指向栈底指针
}
return 1;
}
//销毁顺序栈
int Destorystack(Sqstack *s){
if(s->base){
free(s->base);
s->stacksize=0;
s->top=s->base=NULL;
}
return 1;
}
//顺序栈入栈
int Push(Sqstack *s,selemtype e){
if(s->top-s->base==s->stacksize){
return 0; //栈满插入失败
}
*s->top=e;
s->top++;
return 1;
}
//顺序栈出栈
int Pop(Sqstack *s,selemtype *e){ //顺序栈存在,删除s的栈顶元素,用指针e返回删除元素
if(s->base==s->top){
return 0; //栈空,内无元素无法进行出栈操作
}
e=*s->top;
s->top--;
return 1;
}
6.1链栈的表示和实现
6.2链栈的表示
6.3链栈的实现
算法1.链栈的初始化
算法2判断链栈是否为空
算法3链栈的入栈
算法4链栈的出栈
算法5取栈顶元素
链栈的代码实现
#incldue<stdlib.h>
typedef int selemtype;
typedef struct Stacknode{
selemtype data; //链栈的结点
struct Stacknode *next;
}Stacknode,*LinkStack;
LinkStack s;
//在链栈中栈顶为指向头结点的指针,占地为为结点,链表的头指针就是栈顶
//链栈的初始化
void Initstack(LinkStack s){
//构造一个空栈,栈顶指针为空
s=NULL;
return 0;
}
//判断链栈是否为空
int StackEmpty(LinkStack s){
if(s=NULL){
rerurn 1;
}
else return 0;
}
//链栈的入栈
int push(LinkStack s,selemtype e){
Stacknode *p=(Stacknode*)malloc(sizeof(Stacknode));//生成新结点p
p->data=e; //将新结点data赋值e
p->next=s; // 将新接待你插入栈顶
s=p; //修改栈顶指针
return 1;
}
//链栈的出栈
int Pop(LinkStack s,selemtype *e){
if(s=NULL){
return 0; //链栈为空栈
}
*e=s->data;//将出栈的元素交给指针e
Stacknode *p; //定义指针p,用于保存出栈结点的地址
p=s; //p指向栈顶结点(头结点)
s=s->next; //栈顶指针下移
free(p); //释放出栈结点的空间
return 1;
}
7.1栈和递归
7.2递归的定义
7.3函数的调用过程
7.4递归的优缺点
8.1队列的表示和实现
8.2相关术语
常用循环顺序队列,队列是先进先出的数据结构,FIRST IN FIRST OUT(FIFO)结构
8.3相关概念
8.4 队列的结构定义
队列的结构定义中,表述的头指针和尾指针并非真正的指针,而是表示数组下标的整型变量
8.5队列基本操作示意图
8.6队列的假溢出
8.7循环队列
队列判断队空和队满,循环队列中判断队空和队满的条件相同,这时候就需要想办法去识别队列的当前状态到底是空的还是满队的状态,可以设置一个flag来记录当前队列中的元素个数,但是这样会消耗一定的内存空间还可能降低程序运行的效率,目前最常用的方法是舍弃,队列的一个元素的空间,在只剩下一个空间的时候就认为当前队列已经处于满队的状态,但是实际还剩余一个元素的内存空间。
这时候,队空的判断条件是front==rear,但是队满的条件就变成了(rear+1)%maxsize==front,就可以对队空和队满的判断条件进行区分。
9.1队列的顺序表示和实现
9.2循环队列的结构体定义
9.3循环队列的初始化
9.4求队列的长度
9.5循环队列入队
9.6循环队列出队
9.7取队头元素
9.8循环队列代码实现
#include<stdilb.h>
#define maxsize 100
typedef int qelemtype;
typedef struct{
qelemtype *base; //动态分配内存空间
int front; //头指针,若队列不空,指向队头元素
int rear ; //尾指针,若队列不空,指向队尾元素的下一个位置
}SqQueue;
//街斗体的指针,并非指针变量而是指向顺序表元素下标的整型变量
//初始化队列
int InitQueue(SqQueue *q){
q->base=(qelemtype)malloc(sizeof(qelemtype)*maxsize);//动态分配空间
if(!q->base){
return ; //内存分配失败返回0
}
q->front=q->rear=0;//将头和尾指针变为0,队列为空
return ;
}
//求队列的长度
int QueueLength(SqQueue *q){
return ((q->rear-q->front+maxsize)%maxsize);
}
//循环队列入队
int Enqueue(SqQueue *q,qelemtype e){
if((q->rear+1)%maxsize==q->front){
return 0; //队列已满,无法入队
}
q->base[q->rear]=e;//将新元素加入队尾
q->rear=(q->rear+1)%maxsize;//将队尾指针+1
return 1;
}
//循环队列出队
int Outqueue(SqQueue *q,qelemtype *e){
if(q->front==q->rear){
return 0; //队空,无法出队
}
*e=q->base[q->front];
q->front=(q->front+1)%maxsize;
return 1;
}
//取队头元素
qelemtype GetHead(SqQueue *q){
if(q->front!=q->rear){
return 0;//队列为空,无法取元素
}
return q->base[q->front]; //返回头指针元素的值,队头指针不变
}
10.1链队的表示和实现
10.2链队的结构体定义
10.3链队列运算指针的变化情况
10.4链队的初始化
10.5销毁链队列
在销毁链队列的时候,你可以另外定义一个指针p来作为标记,方标指针移动后释放结点也可以用尾指针rear来作为标记指针用于元素的释放,在销毁队列的时候,尾指针几乎不起作用,这样做就不用再申请内存空间了
10.6链队的入队操作
10.7链队的出队操作
10.8求链队的对头元素
10.9链队的基本操作代码实现
#include<stdilb.h>
typedef int qelemtype;
typedef struct qnode{
qelemtype data; //定义队列结点的结构体
struct qnode *next;
}Qnode,*Queueptr;
//定义一个指向队列结点的指针
typedef struct{
Queueptr front; //队头指针
Queueptr rear; // 队尾指针
}LinkQueue;
//初始化链队
int InitQueue(LinkQueue Q){
Q.front=Q.rear=(Queueptr)malloc(sizeof(Qnode));
if(!Q.front){
return 0;
}
Q.front->next=NULL;
return 1;
}
//销毁队列
int Destory(LinkQueue Q){
Qnode *p;
while(Q.front){ //判断是否到尾部
p=Q.front->next; //让指针p指向当前结点的next结点
free(Q.front); //释放当前结点的内存空间
Q.front=p;
}
}
//链队的入队
int Enqueue(LinkQueue Q,qelentype e){
Qnode *p;
p=(Qnode *)malloc(sizeof(Qnode));
if(!p){
return 0; //内存分配失败,返回0
}
p->data=e;
p->next=NULL; //将插入的元素放入data域,由于只能插入到队尾,将next域设为NULL
Q.rear->next=p;
Q.rear=p;
return 1;
}
//链队的出队
int OutQueue(LinkQueue *Q,qelemtype *e){
Qnode *p;
if(Q->front==Q->rear){
return 0;
}
p=Q->front->next //设置一个标记指针,方便操作后元素空间的释放
*e=p->data;
Q->front->next=p->next;//将头指针后移动一个结点位置
free(p);
return 1;
}