队列概念
只允许在一端进行插入数据,而在另一端进行删除数据的特殊线性表
进行插入操作的一端称为队尾(入队列)
进行删除操作的一端成为队首(出队列)
队列具有先进先出(FIFO)的特性
顺序队列
- 队首不动,出队列时队首后的所有元素向前移动
缺陷:操作时如果出队列次数比较多,则要搬移大量元素
- 队首不动,出队列时队首向后移动一个位置
缺陷:容易造成队列假溢出
假溢出:顺序队列因多次入队列和出队列操作后出现的尚有存储空间但不能再进行入队列操作的溢出
真溢出:顺序队列最大存储空间已经存满而又要进行入队列操作引起的溢出
由此引入了循环队列来解决假溢出,当后面满了就从头开始,直到所存数据数量达到最大存储数。但我们该如何判断队列的空和满呢?
- 少用一个存储单元
- 设置一个标记位
- 设置一个计数器
实现代码:
//seqqueue.h
#pragma once
#include <stddef.h>
#define SeqQueueMaxSize 1000
typedef char SeqQueueType;
typedef struct SeqQueue{
SeqQueueType data[SeqQueueMaxSize];
//[head, tail)
size_t head;
size_t tail;
//队列中元素个数
size_t size;
}SeqQueue;
void SeqQueueInit(SeqQueue* q);
void SeqQueueDestory(SeqQueue* q);
void SeqQueuePush(SeqQueue* q, SeqQueueType value);
void SeqQueuePop(SeqQueue* q);
int SeqQueueFront(SeqQueue* q, SeqQueueType* value);
//seqqueue.c
#include "seqqueue.h"
#include <stdio.h>
void SeqQueueInit(SeqQueue* q){
if(q == NULL){
//非法输入
return;
}
q->head = q->tail = 0;
q->size = 0;
}
void SeqQueueDestory(SeqQueue* q){
if(q == NULL){
//非法输入
return;
}
q->head = q->tail = 0;
q->size = 0;
}
void SeqQueuePush(SeqQueue* q, SeqQueueType value){
if(q == NULL){
//非法输入
return;
}
if(q->size == SeqQueueMaxSize){
//队列已满
return;
}
q->data[q->tail++] = value;
q->tail %= SeqQueueMaxSize;
//q->tail = (q->tail) & (SeqQueueMaxSize - 1);
++q->size;
}
void SeqQueuePop(SeqQueue* q){
if(q == NULL){
//非法输入
return;
}
if(q->size == 0){
//空队列
return;
}
++q->head;
q->head %= SeqQueueMaxSize;
--q->size;
}
int SeqQueueFront(SeqQueue* q, SeqQueueType* value){
if(q == NULL || value == NULL){
//非法输入
return 0;
}
if(q->size == 0){
//空队列
return 0;
}
*value = q->data[q->head];
return 1;
}
//////////////////////////////////////////////////////////////////////////////
//以下是测试代码
/////////////////////////////////////////////////////////////////////////////
#if 1
void Test(){
SeqQueue q;
SeqQueueInit(&q);
SeqQueuePush(&q, 'a');
SeqQueuePush(&q, 'b');
SeqQueuePush(&q, 'c');
SeqQueuePush(&q, 'd');
SeqQueueType tmp;
SeqQueueFront(&q, &tmp);
printf("tmp expect a, actual %c\n", tmp);
SeqQueuePop(&q);
SeqQueueFront(&q, &tmp);
printf("tmp expect b, actual %c\n", tmp);
SeqQueuePop(&q);
SeqQueueFront(&q, &tmp);
printf("tmp expect c, actual %c\n", tmp);
SeqQueuePop(&q);
SeqQueueFront(&q, &tmp);
printf("tmp expect d, actual %c\n", tmp);
}
int main(){
Test();
return 0;
}
#endif
链式队列
特殊的单链表,只在单链表上进行头删尾插的操作
实现代码:
//linkqueue.h
#pragma once
typedef char LinkQueueType;
typedef struct LinkQueueNode{
LinkQueueType data;
struct LinkQueueNode* next;
}LinkQueueNode;
typedef struct LinkQueue{
LinkQueueNode* head;
LinkQueueNode* tail;
}LinkQueue;
void LinkQueueInit(LinkQueue* q);
void LinkQueueDestroy(LinkQueue* q);
void LinkQueuePush(LinkQueue* q, LinkQueueType value);
void LinkQueuePop(LinkQueue* q);
int LinkQueueFront(LinkQueue* q, LinkQueueType* value);
//linkqueue.c
#include "linkqueue.h"
#include <stdio.h>
#include <stdlib.h>
void LinkQueueInit(LinkQueue* q){
if(q == NULL){
//非法输入
//要求调用者已经为 LinkQueue 变量分配好内存了
return;
}
q->head = NULL;
q->tail = NULL;
}
LinkQueueNode* CreateLinkQueueNode(LinkQueueType value){
LinkQueueNode* new_node = (LinkQueueNode*)malloc(sizeof(LinkQueueNode));
new_node->data = value;
new_node->next = NULL;
return new_node;
}
void DestoryLinkQueueNode(LinkQueueNode* ptr){
free(ptr);
}
void LinkQueuePush(LinkQueue* q, LinkQueueType value){
if(q == NULL){
return;
}
LinkQueueNode* new_node = CreateLinkQueueNode(value);
if(q->head == NULL){
//空队列
q->head = q->tail = new_node;
return;
}
q->tail->next = new_node;
q->tail = q->tail->next;
return;
}
void LinkQueuePop(LinkQueue* q){
if(q == NULL){
//非法输入
return;
}
if(q->head == NULL){
//空队列
return;
}
if(q->head == q->tail){
//只有一个节点
DestoryLinkQueueNode(q->head);
q->head = q->tail = NULL;
return;
}
//有多个节点
LinkQueueNode* to_delete = q->head;
q->head = to_delete->next;
DestoryLinkQueueNode(to_delete);
}
int LinkQueueFront(LinkQueue* q, LinkQueueType* value){
if(q == NULL || value == NULL){
//非法输入
return 0;
}
if(q->head == NULL){
//空队列
return 0;
}
*value = q->head->data;
return 1;
}
void LinkQueueDestroy(LinkQueue* q){
if(q == NULL){
//非法输入
}
while(q->head != NULL){
LinkQueueNode* next = q->head->next;
DestoryLinkQueueNode(q->head);
q->head = next;
}
q->head = NULL;
return;
}
/////////////////////////////////////////////////////////////////////////
//以下是测试函数
/////////////////////////////////////////////////////////////////////////
#if 1
#define TEST_HEADER printf("\n=============%s=============\n", __FUNCTION__)
void TestInit(){
TEST_HEADER;
LinkQueue q;
LinkQueueInit(&q);
}
void Test(){
TEST_HEADER;
LinkQueue q;
LinkQueueInit(&q);
LinkQueuePush(&q, 'a');
LinkQueuePush(&q, 'b');
LinkQueuePush(&q, 'c');
LinkQueuePush(&q, 'd');
LinkQueueType tmp;
LinkQueueFront(&q, &tmp);
printf("tmp expect a, actual %c\n", tmp);
LinkQueuePop(&q);
LinkQueueFront(&q, &tmp);
printf("tmp expect b, actual %c\n", tmp);
LinkQueuePop(&q);
LinkQueueFront(&q, &tmp);
printf("tmp expect c, actual %c\n", tmp);
LinkQueuePop(&q);
LinkQueueFront(&q, &tmp);
printf("tmp expect d, actual %c\n", tmp);
LinkQueuePush(&q, 'a');
LinkQueueDestroy(&q);
int ret = LinkQueueFront(&q, &tmp);
printf("ret expect 0, actual %d\n", ret);
}
int main(){
Test();
return 0;
}
#endif