对链式队列的实现(C语言)

本文详细介绍了链式队列的数据结构定义及各个操作函数的实现,包括初始化、元素插入、取队首元素、删除队首元素等,并通过单元测试验证了各功能的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对链式队列的实现

实现的具体过程:

  • 结构体定义和函数声明
  • 队列的初始化
  • 队列的尾插入
  • 取队首元素
  • 删除队首元素
  • 判断队列是否为空
  • 求队列元素的个数
  • 队列的销毁
  • 单元测试代码

结构体定义内容和函数声明

链式队列需要定义两个指针分别来表示队头和队尾,我们用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;
}

如有错,望指出,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值