队列超详细讲解 | 顺序队列&循环队列&链式队列 双实现 + 完整可运行c语言代码

队列

1.顺序队列(循环)

前置知识

text 复制代码
一种先进先出的结构

​ 先简述下为什么要写循环队列 ----->主要是为了解决 "假溢出"

text 复制代码
就是rear指到最后已经满了 但是同时前面又出队了 这样还有位置但是进不去

循环队列相关

c 复制代码
一个问题 若我们规定空队列时是front == rear 当队列满时呢? 也是front == rear???

**这里我采用浪费一个空间的方法(浪费队列的首空间)(也就是队列首个空间不放元素)

由于rear可能比front大,也可能比front小,所以在他们相差一个位置的时候,就是满的情况
	也可能是相差一整圈,也是满的情况(这种是队列中没有一个出队的) 

这里我们规定队列的最大空间为MaxQueueSize
	
1. front == rear  //队列为空
2. (rear + 1) % MaxQueueSize == front //队列为满

1.入队

text 复制代码
1.判断队列是否已满
2.移动rear指针 
3.放值
  1. 判断队列是否已满------> if ( ( queue->rear + 1 ) % MaxQueueSize == queue->front )

  2. 移动rear指针 ------> queue->rear = ( queue->rear + 1 ) % MaxQueueSize;

  3. 放值 ------> queue->dataqueue-\>rear = e;

text 复制代码
1.判断队列是否已满
2.移动rear指针 
3.放值
c 复制代码
if ((queue->rear + 1) % MaxQueueSize == queue->front) 
{
	fprintf(stderr, "Queue Full!\n");
	return -1;
}

queue->rear = (queue->rear + 1) % MaxQueueSize;

queue->data[queue->rear] = e;

2.出队

text 复制代码
1.判断队列是否为空
2.移动front指针                   
  1. 判断队列是否为空------> if (queue->rear == queue->front)

  2. 移动front指针 ------> queue->front = (queue->front + 1) % MaxQueueSize;

text 复制代码
1.判断队列是否为空
2.移动front指针  
c 复制代码
if (queue->rear == queue->front) 
{
	fprintf(stderr, "Queue Empty!\n");
	return -1;
}

queue->front = (queue->front + 1) % MaxQueueSize;

头文件部分

c 复制代码
typedef int Element;

#define MaxQueueSize 5

typedef struct 
{
	Element data[MaxQueueSize];
	int front;
	int rear;
}ArrayQueue;

//1.初始化循环队列
void initArrayQueue(ArrayQueue* queue);

//2.入队
int enArrayQueue(ArrayQueue* queue, Element e);

//3.出队
int deArrayQueue(ArrayQueue* queue, Element* e);

实现

1.初始化循环队列

c 复制代码
//1.初始化循环队列
void initArrayQueue(ArrayQueue* queue) 
{            
    //初始化
    memset(stack->data, 0, sizeof(stack->data));
	queue->front = queue->rear = 0;    
}

2.入队

c 复制代码
int enArrayQueue(ArrayQueue* queue, Element e) 
{
	//入队相关代码
    
    //1.判断队列是否已满
	if ((queue->rear + 1) % MaxQueueSize == queue->front) {
		fprintf(stderr, "Queue Full!\n");
		return -1;
	}
	//2.移动rear指针
	queue->rear = (queue->rear + 1) % MaxQueueSize;
    
    //3.放值
	queue->data[queue->rear] = e;

	return 0;
}

3.出队

c 复制代码
int deArrayQueue(ArrayQueue* queue, Element* e)   //用e返回队头元素
{
	//出队相关代码
    
    //1.判断队列是否为空
	if (queue->rear == queue->front) {
		fprintf(stderr, "Queue Empty!\n");
		return -1;
	}
    
	//2.移动front指针
	queue->front = (queue->front + 1) % MaxQueueSize;
    
    //通过指针修改外部实参 带出队首元素
	*e = queue->data[queue->front];

	return 0;
}

测试案例

main函数

c 复制代码
void test03() 
{
	 ArrayQueue stu1;
	
    //初始化队列
	 initArrayQueue(&stu1);

    //循环入队5个元素
	 for (int i = 0;i < MaxQueueSize-1;i++) {
		 enArrayQueue(&stu1,i+100);
	 }
    
    //队列已满 入队失败
	 enArrayQueue(&stu1,520);
    
    //出队 并查看队列中元素
	 Element x1;
	 while (deArrayQueue(&stu1, &x1) != -1) 
     {
		 printf("%d\t", x1);
	 }
    
	 printf("\n");
}

输出结果

c 复制代码
Queue Full!
619     620     621     622     Queue Empty!

2.链式队列

前置知识

text 复制代码
链式队列其实就是单链表 直播不过它只能头进尾出而已

先看下队列的样子吧

1.入队

text 复制代码
这个该往rear的后面插 即尾插 
为了方便出队(如果头插了 出队的时候front也不能往前走啊)

1.创建新结点
2.更新新节点
3.更新队尾的next指针 连接新节点
4.更新队尾指针
  1. 创建新节点 ------> *QueNode new_node = malloc(sizeof(QueNode));

  2. 更新新节点 ------> new_node->next = NULL;

  3. 更新队尾的next指针 连接新节点 ------> queue->rear->next = new_node;

  4. 更新队尾指针 ------> queue->rear = new_node;

text 复制代码
1.创建新结点
2.更新新节点
3.更新队尾的next指针 连接新节点
4.更新队尾指针
c 复制代码
QueNode *new_node = malloc(sizeof(QueNode));
new_node->next = NULL;
queue->rear->next = new_node;
queue->rear = new_node;

2.出队

text 复制代码
1.引入辅助指针tmp备份待删除位置
2.修改队头指针 跳过待删除节点 重新衔接队列
3.删除tmp
  1. 引入辅助指针tmp备份待删除位置 ------> *QueNode tmp = queue->front;

  2. 修改队头指针 跳过待删除节点 重新衔接队列 ------> queue->front = tmp->next;

  3. 删除tmp ------> free(tmp);

text 复制代码
1.引入辅助指针tmp备份待删除位置
2.修改队头指针 跳过待删除节点 重新衔接队列
3.删除tmp

c 复制代码
QueNode *tmp = queue->front;
queue->front = tmp->next;
free(tmp);

头文件部分

c 复制代码
typedef int Element;

// 链式队列的节点
typedef struct _node 
{
	Element data;
	struct _node *next;
} QueNode;

// 链式队列的头节点
typedef struct 
{
	QueNode *rear;         //队列头指针
	QueNode *front;        //队列尾指针
	int cnt;               //用来计数队列中的节点数量 这个其实写不写都可以
	const char *name;      //链式队列名字 写不写都可以 写着玩
} LinkQueue;

//1.创建链式队列
LinkQueue *createLinkQueue(const char *name);

//2.释放链式队列
void releaseLinkQueue(LinkQueue *queue);

//3.入队
int enLinkQueue(LinkQueue *queue, Element e);

//4.出队
int deLinkQueue(LinkQueue *queue, Element *e);

实现

1.创建链式队列

c 复制代码
LinkQueue* createLinkQueue(const char *name) 
{
    //创建链式队列
	LinkQueue* queue = malloc(sizeof(LinkQueue));
	if (queue == NULL) {
		fprintf(stderr, "createLinkQueue malloc failed!\n");
		return NULL;
	}
    
    //初始化
	queue->name = name;
	queue->front =queue->rear = NULL;
	queue->cnt = 0;

    //返回该链式队列
	return queue;
}

2.释放链式队列

c 复制代码
void releaseLinkQueue(LinkQueue* queue) 
{
	if (queue) 
    {
		QueNode *tmp;
		while (queue->front) 
        {    
            //出队相关代码
			tmp = queue->front;
			queue->front = tmp->next;   //不断向后遍历队列中节点
			free(tmp);
            //减少队列中节点数量
			queue->cnt--;
		}
        
		printf("queue have %d node!\n", queue->cnt);
        
        //最后释放队列
		free(queue);
	}
}

3.入队

c 复制代码
// 先有新节点,新节点应该rear的next方向插入,便于front的删除
int enLinkQueue(LinkQueue* queue, Element e) 
{
	QueNode *node = malloc(sizeof(QueNode));
	if (node == NULL) {
		fprintf(stderr, "enLinkQueue new_node malloc failed!\n");
		return -1;
	}
    
    //入队相关代码
	node->data = e;
	node->next = NULL;
	if (queue->rear)    //队列中元素不为空时
    {  
		queue->rear->next = node;
		queue->rear = node;
	} 
    else   //当队列中元素为空时
    {
		queue->rear = queue->front = node;
	}
    
    //增加链式队列中节点数量
	queue->cnt++;
	return 0;
}

4.出队

c 复制代码
int deLinkQueue(LinkQueue* queue, Element* e)   //用e返回队头元素
{
    //判断队列是否为空
	if (queue->front == NULL) 
    {
		fprintf(stderr, "\tqueue empty!\n");
		return -1;
	}
	
    //通过指针修改外部实参 带出队首元素
	*e = queue->front->data;
    
    //出队相关代码
	QueNode *tmp = queue->front;
	queue->front = tmp->next;
	free(tmp);
    
    //减少队列中节点数量
	queue->cnt--;
    
	if (queue->front == NULL) 
    {		// 队列中已经没有元素
		queue->rear = NULL;         //尾指针置空
	}
	return 0;
}

测试案例

main函数

c 复制代码
void test04() 
{
    //创建链式队列
	LinkQueue* queue = creatLinkkQueue("jj");
	if (queue == NULL) {
		return;
	}
    
    //循环入队5个元素
	for (int i = 0; i < 5; i++) 
    {
		enLinkQueue(queue, i + 619);
	}
    
	Element x1;
	printf("%s Queue %d show:", queue->name,queue->cnt);
    
    //出队 队列中所有元素
	while (deLinkQueue(queue, &x1) != -1) 
    {
		printf("\t%d", x1);
	}
	printf("\n");
    
    //释放该队列
	releaseLinkQueue(queue);
}

int main()
{
    test04();
    return 0;
}

输出结果

c 复制代码
jj Queue 5 show:        619     620     621     622     623     queue empty!

queue have 0 node!

​ 嘻嘻嘻嘻 队列部分到此结束😆😆

​ (有错误欢迎指出) (疑问也是)❤️❤️😍😍💖💖

至此 队列小节结束 持续更新中... ...