1.队列的概念
队列性质:先进先出
队列的操作:
入队
出队
2.链式队列
为了实现队列的先进先出的原理,链式存储里面可以采用头插法和尾删法或者尾插法和头删法实现功能,但是尾插法和尾删法都需要每次遍历链表,效率比较低
所以我们可以定义两个指针变量,一个front保存头结点的地址,另一个rear保存最后一个结点的地址
入队操作时将新节点插入到rear对应结点的后面,然后rear保存最后一个结点的地址,出队操作就是将头结点后面的结点删除
3. 链式队列的操作
3.1创建一个空的队列
//创建一个空的队列
linkqueue *LinkqueueCreate()
{
//创建两个指针
linkqueue *q = (linkqueue *)malloc(sizeof(linkqueue));
//创建一个头结点并且让next指针保存NULL标识为空
q->front = (linknode *)malloc(sizeof(linknode));
q->rear = q->front;
q->front->next = NULL;
return q;
}
3.2入队
//入队
void LinkqueueInput(linkqueue *q, DataType value)
{
//申请空间并赋值
linknode *temp = (linknode *)malloc(sizeof(linknode));
temp->data = value;
temp->next = NULL;
//将新结点插入到rear对应结点的后面
//rear结点的指针域保存新结点的地址
q->rear->next = temp;
//新结点的指针域保存NULL
temp->next = NULL;
//rear保存新插入结点的地址
q->rear = temp;
return ;
}
3.3出队
//出队
DataType LinkqueueOutput(linkqueue *q)
{
if(q->front->next == NULL)
{
printf("队列为空\n");
return (DataType)-1;
}
//将front对应结点的后面的结点删除
linknode *temp = q->front->next;
q->front->next = temp->next;
DataType value = temp->data;
free(temp);
temp = NULL;
//当最后一个结点删除之后,需要将rear指针指向头结点
if(q->front->next == NULL)
{
q->rear = q->front;
}
return value;
}
4.相关代码
linqueue.h
#ifndef _LINKQUEUE_H_
#define _LINKQUEUE_H_
#include <stdio.h>
#include <stdlib.h>
//定义数据类型
typedef int DataType;
//定义结点结构体
typedef struct node{
DataType data;
struct node *next;
}linknode;
//定义结构体便于返回操作链式队列的两个指针
typedef struct{
linknode *front; //保存头结点的地址
linknode *rear; //每次保存最后一个结点的地址
}linkqueue;
//创建一个空的队列
linkqueue *LinkqueueCreate();
//入队
void LinkqueueInput(linkqueue *q, DataType value);
//出队
DataType LinkqueueOutput(linkqueue *q);
#endif
linkqueue.c
#include "linkqueue.h"
//创建一个空的队列
linkqueue *LinkqueueCreate()
{
//创建两个指针
linkqueue *q = (linkqueue *)malloc(sizeof(linkqueue));
//创建一个头结点并且让next指针保存NULL标识为空
q->front = (linknode *)malloc(sizeof(linknode));
q->rear = q->front;
q->front->next = NULL;
return q;
}
//入队
void LinkqueueInput(linkqueue *q, DataType value)
{
//申请空间并赋值
linknode *temp = (linknode *)malloc(sizeof(linknode));
temp->data = value;
temp->next = NULL;
//将新结点插入到rear对应结点的后面
//rear结点的指针域保存新结点的地址
q->rear->next = temp;
//新结点的指针域保存NULL
temp->next = NULL;
//rear保存新插入结点的地址
q->rear = temp;
return ;
}
//出队
DataType LinkqueueOutput(linkqueue *q)
{
if(q->front->next == NULL)
{
printf("队列为空\n");
return (DataType)-1;
}
//将front对应结点的后面的结点删除
linknode *temp = q->front->next;
q->front->next = temp->next;
DataType value = temp->data;
free(temp);
temp = NULL;
//当最后一个结点删除之后,需要将rear指针指向头结点
if(q->front->next == NULL)
{
q->rear = q->front;
}
return value;
}
main.c
#include "linkqueue.h"
int main(int argc, char const *argv[])
{
linkqueue *queue = LinkqueueCreate();
LinkqueueInput(queue, 100);
LinkqueueInput(queue, 200);
LinkqueueInput(queue, 300);
LinkqueueInput(queue, 400);
LinkqueueInput(queue, 500);
LinkqueueInput(queue, 600);
printf("出队:%d\n", LinkqueueOutput(queue));
printf("出队:%d\n", LinkqueueOutput(queue));
printf("出队:%d\n", LinkqueueOutput(queue));
printf("出队:%d\n", LinkqueueOutput(queue));
printf("出队:%d\n", LinkqueueOutput(queue));
printf("出队:%d\n", LinkqueueOutput(queue));
printf("出队:%d\n", LinkqueueOutput(queue));
LinkqueueInput(queue, 666);
LinkqueueInput(queue, 777);
LinkqueueInput(queue, 888);
printf("出队:%d\n", LinkqueueOutput(queue));
printf("出队:%d\n", LinkqueueOutput(queue));
printf("出队:%d\n", LinkqueueOutput(queue));
return 0;
}
5. 顺序队列(循环队列)
sequeue.h
#ifndef _SEQUEUE_H_
#define _SEQUEUE_H_
#include <stdio.h>
#include <stdlib.h>
//顺序队列又称之为循环队列
//为了能判断队列为空为满,
//所以如果要存储NUM元素的数组应该定义元素的个数为NUM+1
#define NUM 32
#define N (NUM+1)
//定义数据类型
typedef int DataType;
//定义结构体
typedef struct{
DataType data[N];
int front; //保存出队的元素下标
int rear; //保存入队位置
}sequeue;
//创建一个空的循环队列
sequeue *SequeueCreate();
//判断循环队列是否为满
int SequeueIsFull(sequeue *sq);
//判断循环队列是否为空
int SequeueIsEmpty(sequeue *sq);
//入队
void SequeueInput(sequeue *sq, DataType value);
//出队
DataType SequeueOutput(sequeue *sq);
#endif
sequeue.c
#include "sequeue.h"
//创建一个空的循环队列
sequeue *SequeueCreate()
{
//申请空间
sequeue *sq = (sequeue *)malloc(sizeof(sequeue));
//初始状态让front和rear都保存0标识为空
sq->front = sq->rear = 0;
return sq;
}
//判断循环队列是否为满
int SequeueIsFull(sequeue *sq)
{
return ((sq->rear + 1) % N) == sq->front ? 1 : 0;
}
//判断循环队列是否为空
int SequeueIsEmpty(sequeue *sq)
{
return sq->front == sq->rear ? 1 : 0;
}
//入队
void SequeueInput(sequeue *sq, DataType value)
{
if(SequeueIsFull(sq))
{
printf("队列为满\n");
return ;
}
//将数据保存在rear对应的数组位置上
sq->data[sq->rear] = value;
//rear保存下一个元素的下标
sq->rear = (sq->rear + 1) % N;
return ;
}
//出队
DataType SequeueOutput(sequeue *sq)
{
if(SequeueIsEmpty(sq))
{
printf("队列为空\n");
return (DataType)-1;
}
//定义临时变量保存要出队的数据
DataType value = sq->data[sq->front];
//front后移保存下一个要出队的数据的下标
sq->front = (sq->front + 1) % N;
return value;
}
main.c
#include "sequeue.h"
int main(int argc, char const *argv[])
{
sequeue *sq = SequeueCreate();
SequeueInput(sq, 100);
SequeueInput(sq, 200);
SequeueInput(sq, 300);
SequeueInput(sq, 400);
SequeueInput(sq, 500);
SequeueInput(sq, 600);
while(!SequeueIsEmpty(sq))
{
printf("出队:%d\n", SequeueOutput(sq));
}
return 0;
}