对链式队列的实现
实现的具体过程:
- 结构体定义和函数声明
- 队列的初始化
- 队列的尾插入
- 取队首元素
- 删除队首元素
- 判断队列是否为空
- 求队列元素的个数
- 队列的销毁
- 单元测试代码
结构体定义内容和函数声明
链式队列需要定义两个指针分别来表示队头和队尾,我们用head表示头指针tail表示尾指针,这是队列的结构体,而队列的节点也是一个结构体,其实和链表的结构体特别想象,一个数据data和一个指向下一个节点的next指针。这样我们的链表的结构体定义就完成了
结构体代码
typedef char TypeLinkQueue;
//这里是节点的创建
typedef struct LinkQueueNode{
TypeLinkQueue data;
struct LinkQueueNode *next;
}LinkQueueNode;
//这是队列的结构体
typedef struct LinkQueue{
LinkQueueNode *head;
LinkQueueNode *tail;
}LinkQueue;
函数声明
// 初始化
void InitLinkQueue(LinkQueue **q);
// 队尾插入元素
void PushLinkQueue(LinkQueue **q, TypeLinkQueue value);
// 取队首元素
int TopFindLinkQueue(LinkQueue *q, TypeLinkQueue *top);
// 删除队首元素
void PopLinkQueue(LinkQueue **q);
// 判断队是否为空
int EmptyLinkQueue(LinkQueue *q);
// 求队列中元素的个数
size_t SizeLinkQueue(LinkQueue *q);
// 销毁队列
void DestoryLinkQueue(LinkQueue **q);
函数的定义
队列的初始化
队列初始化,分情况,如果你是想在定义变量时,在栈上开辟好变量,那么就在初始化时候就不需要开辟空间,例如 LinkQueue q,就可以之直接初始化head和tail指针。如果你是只是在栈上开辟出一个指针如,LinkQueue *q,那么必须在初始化时候开辟空间,同时初始化head和tail,这样在传值接受时候需要**来接收二级指针。我在这里采用的是第二种方法。
代码:
void InitLinkQueue(LinkQueue **q)
{
if (q == NULL)
{
return;
}
*q = (LinkQueue *)malloc(sizeof(LinkQueue));
(*q)->head = NULL;
(*q)->tail = NULL;
}
队尾插入元素
队尾插入元素需要注意以下几点:
1)插入判断输入参数是否合法。
2)判断是否是队列要插入的第一个节点,如果是要同时处理tail和head指针,如果不是则只要将节点插入到tail的next指针上,让tail指向tail的next。
3)写个创建节点的小函数,并且对其初始化。
LinkQueueNode *CreatNode(TypeLinkQueue value)
{
LinkQueueNode *new_node = (LinkQueueNode *)malloc(sizeof(LinkQueueNode));
if (new_node == NULL)
{
return NULL;
}
new_node->data = value;
new_node->next = NULL;
return new_node;
}
void PushLinkQueue(LinkQueue **q, TypeLinkQueue value)
{
if (q == NULL || *q == NULL)
{
return;
}
if ((*q)->head == (*q)->tail && (*q)->tail == NULL)
{
(*q)->head = (*q)->tail = CreatNode(value);
}
else
{
(*q)->tail->next = CreatNode(value);
(*q)->tail = (*q)->tail->next;
}
return;
}
取队首元素
首先说明一点,在C语言中只能返回,只能能返回一个值来判断是成功,不能又返回成功和值,怎么说呢?比如 取队首元素成功,那么返回1,那么队首元素如何返回。所以我们这里采用int 型,让调用者自己创建变量传地址进行取值。返回只需要返回取值成功或者失败。
代码
int TopFindLinkQueue(LinkQueue *q, TypeLinkQueue *top)
{
if (q == NULL || top == NULL)
{
return -1;
}
if (q->head == NULL)
{
return 0;
}
*top = q->head->data;
return 1;
}
删除队首元素
删除队首元素需要注意一下几点:
1)判断传入参数是否合法
2)判断队列是否为空
3)为了防止删除最后一个元素后,head指针指向NULL,而tail指针不知到指向那里,那么插入就会插入失败,所以我们分开讨论,如果剩下一个元素,我们在删除的同时将tail指针指向NULL,如果不是剩下不是一个元素,那么我们就将head保存然后指向head的next,释放保存head指针的指针所指向的空间。
代码
void PopLinkQueue(LinkQueue **q)
{
if (q == NULL || *q == NULL)
{
return;
}
if ((*q)->head == NULL)
{
return;
}
if ((*q)->head->next == NULL)
{
LinkQueueNode *to_delete = (*q)->head;
(*q)->head = (*q)->head->next;
free(to_delete);
(*q)->tail = NULL;
}
else
{
LinkQueueNode *to_delete = (*q)->head;
(*q)->head = (*q)->head->next;
free(to_delete);
}
return;
}
判断是否为空
只要看head是否指向NULL
代码
// 是空返回1,不是返回0.
int EmptyLinkQueue(LinkQueue *q)
{
if (q == NULL)
{
return -1;
}
if (q->head == NULL)
{
return 1;
}
return 0;
}
求队列元素个数
从head开始遍历,结束条件为head不等于NULL
代码
size_t SizeLinkQueue(LinkQueue *q)
{
if (q == NULL)
{
return (size_t)-1;
}
LinkQueueNode *cur = q->head;
size_t count = 0;
while (cur != NULL)
{
++count;
cur = cur->next;
}
return count;
队列的销毁
销毁和初始化对应,如果你在初始化的时候选择了前者,那么这里销毁只要把节点释放,让q指针指向NULL就行了,如果是后者,那么就你就要把节点释放,然后需要把*q的空间释放在让*q指向NULL
代码
void DestoryLinkQueue(LinkQueue **q)
{
if (q == NULL || *q == NULL)
{
return;
}
while ((*q)->head != NULL)
{
LinkQueueNode *delete = (*q)->head;
free(delete);
(*q)->head = (*q)->head->next;
}
(*q)->tail = NULL;
free(*q);
*q = NULL;
}
以下是单元测试代码
/////////////////////////////
//以下为测试代码
/////////////////////////////
#define HEAD printf("\n===========%s============\n",__FUNCTION__)
void PrintLinkQueue(LinkQueue *q)
{
LinkQueueNode *cur = q->head;
while (cur != NULL)
{
printf(" %c ", cur->data);
cur = cur->next;
}
printf("\n");
}
void TestInit()
{
HEAD;
LinkQueue *q;
InitLinkQueue(&q);
}
void TestPush()
{
HEAD;
LinkQueue *q;
InitLinkQueue(&q);
PushLinkQueue(&q, 'a');
PushLinkQueue(&q, 'b');
PushLinkQueue(&q, 'c');
PushLinkQueue(&q, 'd');
PrintLinkQueue(q);
}
void TestTop()
{
HEAD;
LinkQueue *q;
InitLinkQueue(&q);
PushLinkQueue(&q, 'a');
PushLinkQueue(&q, 'b');
PushLinkQueue(&q, 'c');
PushLinkQueue(&q, 'd');
TypeLinkQueue top;
int ret = TopFindLinkQueue(q, &top);
printf("except 1 actual %d\n",ret);
printf("except a actual %c\n",top);
}
void TestPop()
{
HEAD;
LinkQueue *q;
InitLinkQueue(&q);
PushLinkQueue(&q, 'a');
PushLinkQueue(&q, 'b');
PushLinkQueue(&q, 'c');
PushLinkQueue(&q, 'd');
PrintLinkQueue(q);
PopLinkQueue(&q);
PrintLinkQueue(q);
PopLinkQueue(&q);
PopLinkQueue(&q);
PopLinkQueue(&q);
PrintLinkQueue(q);
PopLinkQueue(&q);
PrintLinkQueue(q);
PushLinkQueue(&q, 'd');
PrintLinkQueue(q);
}
void TestEmptySize()
{
HEAD;
LinkQueue *q;
InitLinkQueue(&q);
PushLinkQueue(&q, 'a');
PushLinkQueue(&q, 'b');
PushLinkQueue(&q, 'c');
PushLinkQueue(&q, 'd');
int e = EmptyLinkQueue(q);
int s = SizeLinkQueue(q);
printf("except 0 actual %d\n",e);
printf("except 4 actual %d\n",s);
}
void TestDestory()
{
HEAD;
LinkQueue *q;
InitLinkQueue(&q);
PushLinkQueue(&q, 'a');
PushLinkQueue(&q, 'b');
PushLinkQueue(&q, 'c');
PushLinkQueue(&q, 'd');
DestoryLinkQueue(&q);
// PrintLinkQueue(q);
}
int main()
{
TestInit();
TestPush();
TestTop();
TestPop();
TestEmptySize();
TestDestory();
return 0;
}
如有错,望指出,谢谢。