1 队列的特点
先进先出或者说后进后出
2 基于顺序表实现队列的相关操作
2.1 头文件seqqueue.h
//头文件只被编译一次
#pragma once
//宏定义一个标识符,用于打印函数名
#define HEADER printf("============%s==========\n",__FUNCTION__);
//重定义队列元素的数据类型,以便用户修改
typedef char SeqQueueType;
//定义队列的结构体
typedef struct SeqQueue
{
//存放队列数据元素的位置
SeqQueueType* data;
//定义一个变量,用于表示初始化的最大长度
size_t capacity;
//定义两个无符号整型用于标记队列的有效元素范围,有效范围规定为[head,tail)
size_t head;
size_t tail;
//定义一个无符号整型用于标记队列是否已满
size_t size;
}SeqQueue;
//函数声明
//1.初始化SeqQueueInit
void SeqQueueInit(SeqQueue* queue);
//2.销毁SeqQueueDestroy
void SeqQueueDestroy(SeqQueue* queue);
//3.打印SeqQueuePrintChar
void SeqQueuePintChar(SeqQueue* queue,char* msg);
//4.入队列SeqQueuePush
void SeqQueuePush(SeqQueue* queue,SeqQueueType value);
//5.扩容SeqQueueReset
void SeqQueueReset(SeqQueue* queue);
//6.出队列SeqQueuePop
void SeqQueuePop(SeqQueue* queue);
//7.取队首元素SeqQueueFront
int SeqQueueFront(SeqQueue* queue,SeqQueueType* value);
2.2 初始化
//思路:开辟空间、初始队列的有效元素size为0,有效范围也为0,故head=0,tail=0
void SeqQueueInit(SeqQueue* queue){
//非法输入
if(queue==NULL)
return;
//初始化开辟空间的大小
queue->capacity=100;
//开辟空间
queue->data=(SeqQueueType*)malloc((queue->capacity)*sizeof(SeqQueueType));
//初始化size
queue->size=0;
//初始化head、tail
queue->head=0;
queue->tail=0;
}
2.3 销毁
//思路:将开辟的空间释放并将初始开辟的空间大小capacity置为0以及队列的有效元素size置为0,有效范围也置为为0,故head=0,tail=0
void SeqQueueDestroy(SeqQueue* queue){
//非法输入
if(queue==NULL)
return;
//释放空间
free(queue->data);
//将初始开辟空间大小置为0
queue->capacity=0;
//将队列的有效元素个数size置为0
queue->size=0;
//将队列的有效范围置为0,即head=0、tail=0
queue->head=0;
queue->tail=0;
}
2.4 入队列
//思路:将有效元素个数size加1并将tail后移一位
//tail后移时有两种情况:1.tail<SeqQueueMaxSize时直接tail++ 2.tail>=SeqQueueMaxSize时,将tail=0
void SeqQueuePush(SeqQueue* queue,SeqQueueType value){
//非法输入
if(queue==NULL)
return;
//判断队列是否已满
if(queue->size>=queue->capacity)
{
//扩容
SeqQueueReset(queue);
}
//正常入队列
queue->data[queue->tail]=value;
queue->tail++;
//判断tail是否超出SeqQueueMaxSize的范围
if(queue->tail>queue->capacity)
{
queue->tail=0;
}
//有效元素个数size++
queue->size++;
}
//扩容//思路:1.新开辟一块更大的空间 2.将原有的数据进行搬运 3.释放之前的内存空间
void SeqQueueReset(SeqQueue* queue){
//非法输入
if(queue==NULL)
return;
//有效元素个数size小于SeqQueueMaxSize时
if(queue->size<queue->capacity)
return;
//新开辟空间
queue->capacity=2*(queue->capacity)+1;
SeqQueueType* new_data=(SeqQueueType*)malloc((queue->capacity)*sizeof(SeqQueueType));
//将原有数据进行搬运
if(queue->head<queue->tail)
{
size_t i=0;
size_t j=0;
for(i=queue->head;i!=queue->tail;i++)
{
new_data[j]=queue->data[i];
j++;
}
}
else
{
size_t i=queue->head;
size_t j=0;
for(i=queue->head;i<queue->capacity;i++)
{
new_data[j]=queue->data[i];
j++;
}
for(i=0;i<queue->tail;i++)
{
new_data[j]=queue->data[i];
j++;
}
}
//释放原有内存空间
free(queue->data);
queue->data=new_data;
}
2.5 出队列
//思路:将表示有效元素范围的head后移一位,即将head加1,并将有效元素个数size进行减1
void SeqQueuePop(SeqQueue* queue){
//非法输入
if(queue==NULL)
return;
//判断队列是否为空
if(queue->size==0)
return;
//对head加1
queue->head++;
//判断对head加1后head是否是合法范围
if(queue->head>=queue->capacity)
queue->head=0;
//对有效元素个数size进行减1
queue->size--;
}
2.6 取队首元素
//思路:队首元素即queue->data[queue->head]所表示的元素
//需要返回两个有效信息:1.取队首元素是否成功,用返回值传出 2.队首元素的值,用输出参数传出
int SeqQueueFront(SeqQueue* queue,SeqQueueType* value){
//非法输入
if(queue==NULL||value==NULL)
return 0;
//判断队列是否为空
if(queue->size==0)
return 0;
//进行读取队首元素
*value=queue->data[queue->head];
return 1;
}
2.7 测试代码是否正确
为了测试代码的方便需要写打印栈中元素的函数
void SeqQueuePrintChar(SeqQueue* queue,char* msg)
{
//先打印一行字符串
printf("%s\n",msg);
//非法输入
if(queue==NULL||msg==NULL)
return;
//空队列
if(queue->size==0)
return;
if(queue->head<queue->tail)
{
size_t i=0;
for(i=queue->head;i!=queue->tail;i++)
{
printf("%c ",queue->data[i]);
}
}
else
{
size_t i=queue->head;
for(i=queue->head;i<queue->capacity;i++)
{
printf("%c ",queue->data[i]);
}
for(i=0;i<queue->tail;i++)
{
printf("%c ",queue->data[i]);
}
}
printf("\n");
}
//1.测试SeqQueuePush
void Test_SeqQueuePush(){
HEADER;
SeqQueue queue;
SeqQueueInit(&queue);
SeqQueuePush(&queue,'a');
SeqQueuePush(&queue,'b');
SeqQueuePush(&queue,'c');
SeqQueuePrintChar(&queue,"入队列'a''b''c'");
}
//2.测试SeqQueuePop
void Test_SeqQueuePop(){
HEADER;
SeqQueue queue;
SeqQueueInit(&queue);
SeqQueuePush(&queue,'a');
SeqQueuePush(&queue,'b');
SeqQueuePush(&queue,'c');
SeqQueuePop(&queue);
SeqQueuePrintChar(&queue,"出队列一次");
SeqQueuePop(&queue);
SeqQueuePrintChar(&queue,"出队列两次");
SeqQueuePop(&queue);
SeqQueuePop(&queue);
SeqQueuePrintChar(&queue,"尝试对空队列出队列");
}
//3.测试SeqQueueFront
void Test_SeqQueueFront(){
HEADER;
SeqQueue queue;
SeqQueueType value;
SeqQueueInit(&queue);
SeqQueuePush(&queue,'a');
SeqQueuePush(&queue,'b');
SeqQueuePush(&queue,'c');
int ret=SeqQueueFront(&queue,&value);
printf("expected 1,actual %d\n",ret);
printf("expected a,actual %c\n",value);
SeqQueuePop(&queue);
ret=SeqQueueFront(&queue,&value);
printf("expected 1,actual %d\n",ret);
printf("expected b,actual %c\n",value);
SeqQueuePop(&queue);
SeqQueuePop(&queue);
ret=SeqQueueFront(&queue,&value);
printf("expected 0,actual %d\n",ret);
}
/*================主函数===============*/
int main()
{
Test_SeqQueuePush();
Test_SeqQueuePop();
Test_SeqQueueFront();
return 0;
}
3 基于链表实现队列的相关操作
3.1 头文件linkqueue.h
//头文件只被编译一次
#pragma once
//宏定义标识符,用于打印函数名
#define HEADER printf("==============%s============\n",__FUNCTION__);
//为了方便用户修改元素数据类型
typedef char LinkType;
//队列节点的结构体
typedef struct LinkQueue
{
LinkType data;
struct LinkQueue* next;
}LinkQueue;
3.2 初始化
//思路:将头指针置为NULL时,初始化成功
void LinkQueueInit(LinkQueue** pqueue){
//非法输入
if(pqueue==NULL)
return;
//修改头指针的指向为NULL
(*pqueue)=NULL;
}
3.3 销毁
//思路:对队列进行遍历去销毁每一个节点
void LinkQueueDestroy(LinkQueue** pqueue){
//非法输入
if(pqueue==NULL)
return;
//空队列时
if((*pqueue)==NULL)
return;
//遍历释放每一个节点
LinkQueue* cur=*pqueue;
while(cur!=NULL)
{
LinkQueue* next=cur->next;
free(cur);
cur=next;
}
}
3.4 入队列
//思路:利用尾插法进行入队列操作
void LinkQueuePush(LinkQueue** pqueue,LinkType value){
//非法输入
if(pqueue==NULL)
return;
//创建新节点
LinkQueue* new_node=(LinkQueue*)malloc(sizeof(LinkQueue));
new_node->data=value;
new_node->next=NULL;
//空队列时
if(*pqueue==NULL)
{
*pqueue=new_node;
return;
}
//非空队列时,找队列的最后一个节点
LinkQueue* cur=*pqueue;
while(cur->next!=NULL)
{
cur=cur->next;
}
cur->next=new_node;
}
3.5 出队列
//思路:利用头删法实现出队列
void LinkQueuePop(LinkQueue** pqueue){
//非法输入
if(pqueue==NULL)
return;
//空链表时
if(*pqueue==NULL)
return;
//找到要删除的节点
LinkQueue* to_delete=*pqueue;
*pqueue=to_delete->next;
//释放要删除的节点
free(to_delete);
}
3.6 取队首元素
//思路:两种情况:1.空队列直接返回 2.取queue所指向位置的元素
//返回两个有效信息:1.执行是否成功,用返回值 2.队首元素的值,用输出参数带出
int LinkQueueFront(LinkQueue* queue,LinkType* value){
//非法输入
if(value==NULL)
return 0; //返回0表示执行失败
//空队列
if(queue==NULL)
return 0;
*value=queue->data;
//返回1表示执行成功
return 1;
}
3.7 测试代码是否正确
为了测试代码的方便需要写打印栈中元素的函数
void LinkQueuePrintChar(LinkQueue* queue,char* msg){
//非法输入
if(msg==NULL)
return;
//打印一行字符
printf("%s\n",msg);
//空队列
if(queue==NULL)
return;
//遍历队列打印
LinkQueue* cur=queue;
for(;cur!=NULL;cur=cur->next)
{
printf("[%c] ",cur->data);
}
printf("\n");
}
//1.测试初始化、销毁、以及空队列的打印
void Test(){
LinkQueue* queue;
LinkQueueInit(&queue);
printf("%p\n",queue);
LinkQueueDestroy(&queue);
printf("%p\n",queue);
LinkQueuePrintChar(queue,"对空队列打印");
}
//2.测试LinkQueuePush
void Test_LinkQueuePush(){
HEADER;
LinkQueue* queue;
LinkQueueInit(&queue);
LinkQueuePush(&queue,'a');
LinkQueuePush(&queue,'b');
LinkQueuePush(&queue,'c');
LinkQueuePrintChar(queue,"入队列'a''b''c'");
}
//3.测试LinkQueuePop
void Test_LinkQueuePop(){
HEADER;
LinkQueue* queue;
LinkQueueInit(&queue);
LinkQueuePush(&queue,'a');
LinkQueuePush(&queue,'b');
LinkQueuePush(&queue,'c');
LinkQueuePop(&queue);
LinkQueuePrintChar(queue,"出队列一次");
LinkQueuePop(&queue);
LinkQueuePrintChar(queue,"出队列两次");
LinkQueuePop(&queue);
LinkQueuePop(&queue);
LinkQueuePrintChar(queue,"尝试对空队列出队");
}
//4.测试LinkQueueFront
void Test_LinkQueueFront(){
HEADER;
LinkQueue* queue;
LinkType value;
LinkQueueInit(&queue);
LinkQueuePush(&queue,'a');
LinkQueuePush(&queue,'b');
LinkQueuePush(&queue,'c');
int ret=LinkQueueFront(queue,&value);
printf("expected 1,actual %d\n",ret);
printf("expected a,actual %c\n",value);
LinkQueuePop(&queue);
ret=LinkQueueFront(queue,&value);
printf("expected 1,actual %d\n",ret);
printf("expected b,actual %c\n",value);
LinkQueuePop(&queue);
LinkQueuePop(&queue);
ret=LinkQueueFront(queue,&value);
printf("expected 0,actual %d\n",ret);
}
/*=============主函数============*/
int main(){
Test();
Test_LinkQueuePush();
Test_LinkQueuePop();
Test_LinkQueueFront();
return 0;
}