队列
队列:只能选取一个端点进行插入操作,另一个端点进行删除操作的线性表。
队列的几个概念
队尾:进行插入的一端。
队首(队头):进行删除的一端。
进队(入队):向队列中插入新元素。
出队(离队):从队列中删除元素。
队列的主要特点:先进先出。
队列的基本运算
1、初始化队列。
2、销毁队列。
3、判断队列是否为空。
4、进队列。
5、出队列。
顺序队
一、非环形队列
顺序队的类型定义
typedef struct{
int data[MaxSize] //MaxSize表示数组的长度
int front,rear; //记录队首和队尾的
}SqQueue;
1、rear 总是记录队尾元素所在的数组下标
2、元素进队,rear增1
3、front指向当前队中队头元素的前一位置
4、元素出队,front增1
5、当rear=MaxSize-1时不能再进队
顺序队的四要素
1、队空条件:front =rear=-1
2、队满条件:rear=MaxSize-1
3、元素进队:rear++;data[rear]=e;
4、元素出队:front++;e=data[front];(把这个元素的值取给e)
1、初始化队列
void InitQueue(SqQueue *&q){
q=(SqQueue *)malloc(sizeof(SqQueue));
q->front=q->rear=-1;
} //构造一个空的队列;
2、销毁队列
void DestroyQueue(SqQueue *&q){
free(q);
} //释放掉q的空间
3、判断队列是否为空
bool QueueEmpty(SqQueue *q){
return (q->front==q->rear);
} //如果front==rear的话说明时空队列
4、进队列
bool enQueue(SqQueue *&q,int e){
if(q->rear==MaxSize-1){
return false;
} //判断是否队列已满
p->rear++;
p->data[rear]=e;
return true; //入队
}
5、出队列
bool deQueue(SqQueue *&q,int &e){
if(q->front==q->rear){
return false;
}
q->front++;
e=q->data[q->front]; //front是记录队首的前一个位置的
return true;
}
二、环形队列(循环队列)
假溢出:采用rear==MaxSize-1作为队满条件的话,可能在队满条件满足时,队中还有空出的位置。
解决假溢出的方案就是将队列设计成环形队列。
环形队列的四要素:
1、队空条件:front=rear;
2、队满条件:(rear+1)%MaxSize = front;
3、进队:rear=(rear+1)%MaxSize;data[rear]=e;
4、出队:front=(front+1)%MaxSize;e=data[front];
环形队列的队首,队尾,元素个数有着以下的关系:
count==(rear-front+MaxSize)%MaxSize;
rear==(front+count)%MaxSize;
front==(rear-count+MaxSize)%MaxSize;
所有,这三者知道其中任意两者可以求出剩余一者。(可以用元素个数代替队尾)
typedef struct{
int data[MaxSize];
int front; //队头
int count; //元素个数
}QuType; //此环形队列可最多放MaxSize个元素
1、环形队列的初始化
void InitQueue(QuType *&qu){
qu=(QuType*)malloc(sizeof(QuType));
qu->front=0;
qu->count=0;
}
2、环形队列的进队
bool EnQueue(QuType *&qu,int x){
int rear; //一个局部变量,qu中不保存的临时队尾
if(qu->count==MaxSize){
return false; //判断是否队满
}else{
rear=(qu->front+qu->count)%MaxSize;//求队尾
rear=(rear+1)%MaxSize;//做环形队列里的入队操作
qu->data[rear]=x;
qu->count++;//入队后元素数加一
return true;
}
}
3、环形队列的出队
bool DeQueue(QuType *&qu,int &x)
{if(qu->count==0){
return false; //判断是否空队
}else{
qu->front=(qu->front+1)%MaxSize;
x=qu->data[qu->front]; //做环形队列里的出队操作
qu->count--; //元素数减一
return true;
}
}
4、循环队列判断是否队空
bool QueueEmpty(QuType *qu){
return (qu->count==0);
}
链队
链队:就是以链式存储结构为存储结构的队列。
链队中有两个部分,一个部分是链体本身,另一个是队首和队尾指针,所以来定义一个链队的类型。
typedef struct qnode{
int data;
struct qnode *next
}QNode; //链体
typedef struct{
QNode *front; //指向单链表的队头
QNode *rear; //指向单链表的队尾
}LiQueue;
链队的四要素:
1、队空条件:front=rear=NULL
2、队满条件:和链栈一样不考虑
3、进队:将元素插到单链表表尾
4、出队:删除单链表首数据节点
1、初始化链队
void InitQueue(LiQueue *&q){
q=(LiQueue *)malloc(sizeof(LiQueue));
q->front=q->rear=NULL;
}
2、销毁队列
void DestroyQueue(LiQueue *&q){
QNode *p=q->front,*r;
if(p!=NULL){
r=p->next;
while(r!=NULL){
free(p);
p=r;
r=p->next;
}
}
free(p); //释放掉单链表里的最后一个链节
free(q);//释放掉队首队尾指针
}
3、判断队列是否为空
bool QueueEmpty(LiQueue *q){
return (q->rear==NULL);
}
4、进队
void enQueue(LiQueue*&q,int e){
QNode *p;
p=(QNode*)malloc(sizeof(QNode));
p->date=e;
p->next=NULL;
if(q->rear==NULL){ //如果是空队列
q->front=q->rear=p;
}else{ //非空队列
q->rear->next=p;
q->rear=p;
}
}
5、出队
bool deQueue(LiQueue *&q,int &e){
QNode *t;
if(q->rear==NULL){
return false; //空队的情况
}
t=q->front;
if(q->front==q->rear){
q->front=q->rear=NULL; //只有一个节点的队列
}else{
q->front=q->front->next;//有多个节点
}
e=t->data;
free(t);
return true;
}
不带队首指针的链队
不带队首指针的链队,就是只有一个队尾的rear指针指着队尾,然后用队尾节点的指针指向队头。
简单来说就是把普通链队里的单链表变成了循环链表,并且用一个指针取记录不断插进来的新元素。