队列是一种特殊的线性表,而线性表有顺序和链式存储两种,这里只讨论单向链式链表实现的队列模型,队列遵循的原则是先进先出,因此不管以链表的头部和尾部作为队列的头部,当弹出和压入元素的时候都会设计到队列中元素的移动。这里以链表头部为队列的尾部,以链表的尾部做为队列的头部,即压入元素时采用头插法,弹出元素时采用尾出法。
详细讲解参照https://www.bilibili.com/video/av27904891/?p=1
本次使用工具为vs2017,作者水平有限,若有问题请指出。
队列头文件:Queue_Link_C.h
#pragma once
typedef void _Queue;
typedef void _QueueItem;
typedef struct QueueNode
{
struct QueueNode *Next;
_Queue *data;
}QueueNode;
typedef struct Queue
{
QueueNode QueueHead;
int QueueLen;
}Queue;
//创建队列
_Queue *CreateQueue();
//往队列里面压入元素
int Push_Item(_Queue *_queue, _QueueItem *_item);
//从队列头部弹出元素
_QueueItem *Pop_Item(_Queue *_queue);
//获取队列头元素
_QueueItem *GetHeadItem(_Queue *_queue);
//获取队列的元素个数
int GetItemNum(_Queue *_queue);
//清空队列
int ClearQueue(_Queue *_queue);
//销毁队列
int DestoryQueue(_Queue **_queue);
队列源文件:Queue_Link_C.cpp
# include"pch.h"
# include"Queue_Link_C.h"
# include<stdio.h>
# include<stdlib.h>
//创建队列
_Queue *CreateQueue()
{
Queue *queue = (Queue *)malloc(sizeof(Queue));
if (queue == NULL)
{
printf("Malloc Queue Error : CreateQueue() \n");
return NULL;
}
queue->QueueLen = 0;
queue->QueueHead.data = NULL;
queue->QueueHead.Next = NULL;
return (_Queue *)queue;
}
//往队列里面压入元素
int Push_Item(_Queue *_queue, _QueueItem *_item)
{
int ret = 0;
if (_queue == NULL || _item == NULL)
{
printf("Parameters Error : Push_Item() \n");
ret = -1;
return ret;
}
//数据转换
Queue *queue = (Queue *)_queue;
//分配数据节点
QueueNode *queuenode = (QueueNode *)malloc(sizeof(QueueNode));
queuenode->data = _item; //把数据挂在节点上
queuenode->Next = NULL; //节点 == NULL
//这里用头插法
if (queue->QueueLen == 0) //队列里面没有数据
{
queue->QueueHead.Next = queuenode;
queue->QueueLen++;
}
else //队列里面有数据
{
queuenode->Next = queue->QueueHead.Next;
queue->QueueHead.Next = queuenode;
queue->QueueLen++;
}
return ret;
}
//从队列头部弹出元素
_QueueItem *Pop_Item(_Queue *_queue)
{
if (_queue == NULL)
{
printf("Parameters Error : Pop_Item() \n");
return NULL;
}
//数据转换
Queue *queue = (Queue *)_queue;
QueueNode *current = queue->QueueHead.Next; //current指向0号元素
if (queue->QueueLen == 0) //队列中没有元素
{
printf("Queue is empty,can't pop element : Pop_Item() \n");
return NULL;
}
for (int i=0; i<queue->QueueLen-1; i++) //循环完了之后current指向最后一个元素
{
current = current->Next;
}
queue->QueueLen--;
return current->data;
}
//获取队列头元素
_QueueItem *GetHeadItem(_Queue *_queue)
{
if (_queue == NULL)
{
printf("Parameters Error : GetHeadItem() \n");
return NULL;
}
//数据转换
Queue *queue = (Queue *)_queue;
QueueNode *current = queue->QueueHead.Next; //current指向0号元素
if (queue->QueueLen == 0) //队列中没有元素
{
printf("Queue is empty,can't get element : GetHeadItem() \n");
return NULL;
}
for (int i = 0; i < queue->QueueLen - 1; i++) //循环完了之后current指向最后一个元素
{
current = current->Next;
}
return current->data;
}
//获取队列的元素个数
int GetItemNum(_Queue *_queue)
{
int ret = 0;
int stacklen = 0;
if (_queue == NULL)
{
printf("Parameters Error :GetItemNum() \n");
ret = -1;
return ret;
}
//数据类型转换
Queue *queue = (Queue *)_queue;
return queue->QueueLen;
}
//清空队列
int ClearQueue(_Queue *_queue)
{
//由于节点是自己malloc出来的,必须手动清除掉
int ret = 0;
if (_queue == NULL)
{
printf("Parameters Error :ClearQueue() \n");
ret = -1;
return ret;
}
//数据转换
Queue *queue = (Queue *)_queue;
QueueNode *current = queue->QueueHead.Next; //current指向0号元素
QueueNode *temp = NULL; //temp = NULL
if (queue->QueueLen <= 0) //队列里面没有元素
{
ret = 0;
return ret;
}
else if(queue->QueueLen == 1) //队列里面元素个数只有1个
{
if (current != NULL)
{
free(current);
}
queue->QueueLen = 0;
queue->QueueHead.data = NULL;
queue->QueueHead.Next = NULL;
}
else //队列里面元素个数大于1
{
for (int i = 0; i < queue->QueueLen - 1; i++)
{
if (current != NULL)
{
temp = current->Next;
free(current);
current = temp;
}
queue->QueueLen = 0;
queue->QueueHead.data = NULL;
queue->QueueHead.Next = NULL;
}
}
return ret;
}
//销毁队列
int DestoryQueue(_Queue **_queue)
{
//由于节点是自己malloc出来的,必须手动清除掉
int ret = 0;
if (_queue == NULL)
{
printf("Parameters Error :ClearQueue() \n");
ret = -1;
return ret;
}
//数据转换
Queue **queue = (Queue **)_queue;
QueueNode *current = (*queue)->QueueHead.Next; //current指向0号元素
QueueNode *temp = NULL; //temp = NULL
if ((*queue)->QueueLen <= 0)//队列里面没有元素
{
ret = 0;
(*queue)->QueueLen = 0;
(*queue)->QueueHead.data = NULL;
(*queue)->QueueHead.Next = NULL;
}
else if ((*queue)->QueueLen == 1)//队列里面元素个数只有1个
{
if (current != NULL)
{
free(current);
}
(*queue)->QueueLen = 0;
(*queue)->QueueHead.data = NULL;
(*queue)->QueueHead.Next = NULL;
}
else//队列里面元素个数大于1
{
for (int i = 0; i < (*queue)->QueueLen - 1; i++)
{
if (current != NULL)
{
temp = current->Next;
free(current);
current = temp;
}
(*queue)->QueueLen = 0;
(*queue)->QueueHead.data = NULL;
(*queue)->QueueHead.Next = NULL;
}
}
//同一销毁头指针
*queue = NULL;
return ret;
}
测试队列功能源文件:Queue_Link_C_Test.cpp
# include"pch.h"
# include"Queue_Link_C.h"
# include<stdio.h>
# include<stdlib.h>
# include"string"
typedef struct person
{
char name[16];
int age;
}person;
//测试person类型的数据
void test_person()
{
person p1, p2, p3, p4, p5, p6, p7, p8;
strcpy_s(p1.name, sizeof("aaa"), "aaa");
strcpy_s(p2.name, sizeof("bbb"), "bbb");
strcpy_s(p3.name, sizeof("ccc"), "ccc");
strcpy_s(p4.name, sizeof("ddd"), "ddd");
strcpy_s(p5.name, sizeof("eee"), "eee");
strcpy_s(p6.name, sizeof("fff"), "fff");
strcpy_s(p7.name, sizeof("ggg"), "ggg");
strcpy_s(p8.name, sizeof("hhh"), "hhh");
p1.age = 81;
p2.age = 82;
p3.age = 83;
p4.age = 84;
p5.age = 85;
p6.age = 86;
p7.age = 87;
p8.age = 88;
person *data = NULL;
int ret = 0;
void *queue = CreateQueue();
ret = Push_Item(queue, &(p1));
ret = Push_Item(queue, &(p2));
ret = Push_Item(queue, &(p3));
ret = Push_Item(queue, &(p4));
ret = Push_Item(queue, &(p5));
//连续读取和弹出5个元素
printf("测试 压入,读取,弹出数据\n");
for (int i = 0; i < 3; i++) //操作5次
{
data = (person*)GetHeadItem(queue);
if (data != NULL)
{
printf("%s %d \n", data->name ,data->age);
}
data = (person *)Pop_Item(queue);
if (data != NULL)
{
printf("%s %d \n", data->name, data->age);
}
}
//测试清空队列
printf("\n测试清空队列后, 压入,读取,弹出数据\n");
ret = ClearQueue(queue);
if (ret == 0) //清空成功
{
ret = Push_Item(queue, &(p7));
ret = Push_Item(queue, &(p7));
for (int i = 0; i < 2; i++) //操作2次
{
data = (person*)GetHeadItem(queue);
if (data != NULL)
{
printf("%s %d \n", data->name, data->age);
}
data = (person *)Pop_Item(queue);
if (data != NULL)
{
printf("%s %d \n", data->name, data->age);
}
}
}
//测试销毁队列
printf("\n测试销毁队列\n");
ret = Push_Item(queue, &(p7));
ret = Push_Item(queue, &(p8));
ret = Push_Item(queue, &(p8));
DestoryQueue(&queue);
ret = Push_Item(queue,&p7);
}
//测试int类型数据
void test_int()
{
int a[] = { 1,2,3,4,5,6,7,8,9,10,11 };
int *data = NULL;
int ret = 0;
void *queue = CreateQueue();
for (int i=0; i<7; i++) //插入7个元素
{
ret = Push_Item(queue,a+i);
if (ret != 0)
{
printf("Push element into queue error : %d \n",i);
break;
}
}
//连续读取和弹出5个元素
printf("测试 压入,读取,弹出数据\n");
for (int i = 0; i < 5; i++) //操作5次
{
data = (int*)GetHeadItem(queue);
if (data != NULL)
{
printf("%d ",*data);
}
data = (int *)Pop_Item(queue);
if (data != NULL)
{
printf("%d ", *data);
}
}
//测试清空队列
printf("\n测试清空队列后, 压入,读取,弹出数据\n");
ret = ClearQueue(queue);
if (ret == 0) //清空成功
{
for (int i = 0; i < 2; i++) //插入2个元素
{
ret = Push_Item(queue, a +8+i);
if (ret != 0)
{
printf("Push element into queue error : %d \n", i);
break;
}
}
for (int i = 0; i < 2; i++) //操作2次
{
data = (int *)GetHeadItem(queue);
if (data != NULL)
{
printf("%d ", *data);
}
data = (int *)Pop_Item(queue);
if (data != NULL)
{
printf("%d ", *data);
}
}
}
//测试销毁队列
printf("\n测试销毁队列\n");
for (int i = 0; i < 3; i++) //插入3个元素
{
ret = Push_Item(queue, a+9);
if (ret != 0)
{
printf("Push element into queue error : %d \n", i);
break;
}
}
DestoryQueue(&queue);
ret = Push_Item(queue, a + 9);
}
int main()
{
test_int();
test_person();
system("pause");
return 0;
}