也没想象中那么神秘的数据结构-先来后到的“队列”(链式队列)

概念

关于队列的相关内容,在之前的文章已经详细介绍过了,请参见《也没想象中那么神秘的数据结构-先来后到的“队列”(顺序队列)》,本文主要将链式队列相关内容。

链式队列:链式队列是基于单链表的存储表示实现的队列,其本质就是线性表的单链表,只不过它只能尾进头出而已。

核心

队列的结构:队列包含两个指针,p_front指向头节点,p_rear指向尾节点,另外头节点固定不变,数据域内容任意指定,一般设定为队列长度。

队列为空的时候,p_front和p_rear均指向头节点,队列不为空的时候,各节点之间通过指针一环扣一环连接起来。

入队:在队尾节点之后插入新节点的操作,插入的时候注意队头指针不变,队尾指针需要改变指针指向。

出队:删除头结点的后继节点,出队的时候注意头结点指针指向的改变。

示例

★包含头文件queue_list.h和源文件queue_list.c(均已验证通过)。

 queue_list.h

/**
 * @Filename : queue_list.h
 * @Revision : $Revision: 1.0 $
 * @Author : Feng(微信公众号:不只会拍照的程序猿)
 * @Description : 链式队列示例
**/

#ifndef __QUEUE_LIST_H__
#define __QUEUE_LIST_H__

#include <stdio.h>
#include <stdlib.h>

#define MAX_SIZE 10         /* 队列最大元素个数 */

/* 队列节点元素定义 */
struct t_node{
    int data;               /* 元素值 */
    struct t_node *p_next;  /* 指向下一个元素 */
};

/* 队列空间定义 */
struct t_queue{
    struct t_node *p_front; /* 指向队头 */
    struct t_node *p_rear;  /* 指向队尾 */
};

/**
 * @初始化队列
 * @p_queue:队列
**/
void queue_init(struct t_queue *p_queue);

/**
 * @清除队列
 * @p_queue:队列
**/
void queue_deinit(struct t_queue *p_queue);

/**
 * @判断队列是否已满
 * @p_queue:队列
 * @返回1表示已满,0表示未满
**/
int queue_is_full(const struct t_queue *p_queue);

/**
 * @判断队列是否已空
 * @p_queue:队列
 * @返回1表示已空,0表示未空
**/
int queue_is_empty(const struct t_queue *p_queue);

/**
 * @获取队列元素个数
 * @p_queue:队列
 * @返回元素个数
**/
int queue_get_size(const struct t_queue *p_queue);

/**
 * @入队列操作
 * @p_queue:队列      data:待插入元素
 * @返回1表示成功,0表示失败
**/
int queue_push(struct t_queue *p_queue, int data);

/**
 * @出队列操作
 * @p_queue:队列      p_data:保存出队列元素
 * @返回1表示成功,0表示失败
**/
int queue_pop(struct t_queue *p_queue, int *p_data);

/**
 * @获取队列顶元素
 * @p_queue:队列      p_data:保存队列顶元素
 * @返回1表示成功,0表示失败
**/
int queue_get_top(const struct t_queue *p_queue, int *p_data);

/**
 * @打印队列元素内容
 * @p_queue:队列
**/
void queue_print(const struct t_queue *p_queue);

#endif

 queue_list.c

/**
 * @Filename : queue_list.c
 * @Revision : $Revision: 1.0 $
 * @Author : Feng(微信公众号:不只会拍照的程序猿)
 * @Description : 链式队列示例
**/

#include "queue_list.h"

/**
 * @创建节点
 * @data:元素值
 * @返回节点地址,NULL表示失败
**/
static struct t_node *creat_node(int data)
{
    struct t_node *p_node = (struct t_node *)malloc(sizeof(struct t_node));

    if (p_node == NULL)
        return NULL;

    p_node->data = data; 
    p_node->p_next = NULL;

    return  p_node;  
}

/**
 * @初始化队列
 * @p_queue:队列
 * @创建头结点,让队头和队尾均指向头结点,头结点数据存储队列长度
**/
void queue_init(struct t_queue *p_queue)
{
    struct t_node *p_head = creat_node(0);  /* 头结点 */

    if (p_head == NULL)
        return;

    p_queue->p_front = p_queue->p_rear = p_head;
}

/**
 * @清除队列
 * @p_queue:队列
**/
void queue_deinit(struct t_queue *p_queue)
{
    struct t_node *p_tmp = NULL, *p_node = p_queue->p_front->p_next;

    while(p_node) {
        p_tmp = p_node;
        p_node = p_node->p_next;
        free(p_tmp);    
    }
    p_queue->p_rear = p_queue->p_front;
    p_queue->p_front->data = 0;
} 

/**
 * @判断队列是否已满
 * @p_queue:队列
 * @返回1表示已满,0表示未满
**/
int queue_is_full(const struct t_queue *p_queue)
{
    return (p_queue->p_front->data >= MAX_SIZE);
}

/**
 * @判断队列是否已空
 * @p_queue:队列
 * @返回1表示已空,0表示未空
**/
int queue_is_empty(const struct t_queue *p_queue)
{
    return (p_queue->p_front->data == 0);
}

/**
 * @获取队列元素个数
 * @p_queue:队列
 * @返回元素个数
**/
int queue_get_size(const struct t_queue *p_queue)
{
    return (p_queue->p_front->data);
}

/**
 * @入队列操作
 * @p_queue:队列      data:待插入元素
 * @返回1表示成功,0表示失败
**/
int queue_push(struct t_queue *p_queue, int data)
{
    struct t_node *p_node = NULL;

    if (queue_is_full(p_queue))
        return 0;

    if ((p_node = creat_node(data)) == NULL)
        return 0;

    p_queue->p_rear->p_next = p_node;
    p_queue->p_rear = p_node;   

    p_queue->p_front->data++;

    return 1;
}

/**
 * @出队列操作
 * @p_queue:队列      p_data:保存出队列元素
 * @返回1表示成功,0表示失败
**/
int queue_pop(struct t_queue *p_queue, int *p_data)
{
    struct t_node *p_node = NULL;

    if (queue_is_empty(p_queue))
        return 0;


    p_node = p_queue->p_front->p_next;
    p_queue->p_front->p_next = p_node->p_next;

    *p_data = p_node->data;
    free(p_node);
    p_queue->p_front->data--;

    return 1;
}

/**
 * @获取队列顶元素
 * @p_queue:队列      p_data:保存队列顶元素
 * @返回1表示成功,0表示失败
**/
int queue_get_top(const struct t_queue *p_queue, int *p_data)
{
    if (queue_is_empty(p_queue))
        return 0;

    *p_data = p_queue->p_front->p_next->data;

    return 1;
}

/**
 * @打印队列元素内容
 * @p_queue:队列
**/
void queue_print(const struct t_queue *p_queue)
{
    struct t_node *p_node = p_queue->p_front->p_next;

    while(p_node) {
        printf("%d ", p_node->data);
        p_node = p_node->p_next;   
    }

    printf("\n");
}

/**
 * @链队列测试代码
**/
int main(void)
{
    int data;
    struct t_queue my_queue;

    queue_init(&my_queue);      /* 初始化队列,此时为空队列 */   
    printf("the queue is %s\n", queue_is_empty(&my_queue) ? "empty" : "not empty");
    printf("---------------------------------------\n");

    /* 压队列,队列:25 41 16 7 8 19 22,元素个数为7 */    
    queue_push(&my_queue, 25);
    queue_push(&my_queue, 41);
    queue_push(&my_queue, 16);
    queue_push(&my_queue, 7);
    queue_push(&my_queue, 8);
    queue_push(&my_queue, 19);
    queue_push(&my_queue, 22);   
    printf("the size of queue is: %d\n", queue_get_size(&my_queue));
    queue_print(&my_queue);
    printf("---------------------------------------\n");

    /* 压队列35 38 11 22(队列已满,入队列失败),队列:25 41 16 7 8 19 22 35 38 11,个数10 */
    queue_push(&my_queue, 35);
    queue_push(&my_queue, 38);
    queue_push(&my_queue, 11);
    queue_push(&my_queue, 22);
    printf("the size of queue is: %d\n", queue_get_size(&my_queue));
    queue_print(&my_queue);
    printf("the queue is %s\n", queue_is_full(&my_queue) ? "full" : "not full");
    printf("---------------------------------------\n");

    /* 队列顶元素为11,第一次出队列11,第二次出队列38,队列:25 41 16 7 8 19 22 35,个数8 */
    if (queue_get_top(&my_queue, &data))
        printf("the top queue data is: %d\n", data);    
    if (queue_pop(&my_queue, &data))
        printf("the pop queue data is: %d\n", data);    
    if (queue_pop(&my_queue, &data))
        printf("the pop queue data is: %d\n", data);   
    printf("the size of queue is: %d\n", queue_get_size(&my_queue));
    queue_print(&my_queue);
    printf("---------------------------------------\n");

    /* 清除队列,个数0 */
    queue_deinit(&my_queue);
    printf("the size of queue is: %d\n", queue_get_size(&my_queue));

    return 0;
}

结论

feng:queue$ gcc -o queue_list queue_list.c
feng:queue$ ./queue_list
the queue is empty
---------------------------------------
the size of queue is: 7
25 41 16 7 8 19 22 
---------------------------------------
the size of queue is: 10
25 41 16 7 8 19 22 35 38 11 
the queue is full
---------------------------------------
the top queue data is: 25
the pop queue data is: 25
the pop queue data is: 41
the size of queue is: 8
16 7 8 19 22 35 38 11 
---------------------------------------
the size of queue is: 0
feng:queue$ 

本示例仅为链式队列示例,公众号也提供顺序栈示例《也没想象中那么神秘的数据结构-先来后到的“队列”(顺序队列)》、《也没想象中那么神秘的数据结构-先来后到的“队列”(循环队列)》以及队列的典型应用示例。

关注

更多精彩内容,请关注微信公众号:不只会拍照的程序猿,本人致力分享linux、设计模式、C语言、嵌入式、编程相关知识,也会抽空分享些摄影相关内容,同样也分享大量摄影、编程相关视频和源码,另外你若想要本文章源码请关注公众号:不只会拍照的程序猿,后台回复:数据结构源码,也可点击此处下载

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不只会拍照的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值