一、简而言之

在百度百科里面摘取了一段关于队列(queue)的介绍:

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。

二、一般而言

这里是对就一般而言, 队列的结构,操作方法等的表述。

2.1 结构

以下为队列的结构示意图

2.2 实现分类

一般来说,队列有两类实现方式:

数组实现:暂时将其称为有限队列,根据创建队列是传入的size,创建相应size的数组来作为队列的载体,一般都会以循环的方式利用数组,也可看作循环队列。

优点:预先分配好内存,在入队和出队过程中不会重新分配内存,有一定时间上的优势。

缺点:因必须预先分配好内存,所以存在内存空间浪费的问题(比如分配了10个元素,但很多时候却只有5个有效元素),元素数目固定,不够灵活。

链表实现:可称其为链式队列,使用链表来实现队列,理论上这样的队列可以无限延伸,当然根据实际需要,可以人为的限制队列长度,让其表现的和数组实现方式差不多。

优点: 无需预先分配内存,所以不存在空间浪费的问题(虽然会多一个指针域,但也基本可以接受),队列长度可限制也可不限制,较为灵活。

缺点: 入队出队分别需要分配和释放元素节点,在时间上会略微慢于数组实现。

总的来说,在可以确定队列长度最大值的情况下,建议用循环队列,如果你无法预估队列的长度时,则用链队列。

2.3 基本操作

这里主要指的是队列的入队(enqueue)与出队(dequeue),对于链式队列来说,其入队和出队也就是链表的尾部插入与移除头部节点,这里就不多说,主要说一下以数组实现的循环链表的具体实现(其中head和tail都是表示数组的下标)。

入队: 如上面的循环队列示意图,入队操作,需要先判断tail节点的下一个位置是否是head,如果是就表示队列已满,无法入队,如果不是,那就可以入队,也即是将元素放入tail的下一个位置,最后将tail加一(也就是指向最终的尾元素),其伪代码如下:

/** 取余保证,当tail = size - 1 时,转回到0 */

int tail = (queue->tail + 1) % queue->size;

if (tail != queue->head)

{ /** 此处这样写,是因为正常情况下,非满的情况多于满了的情况,这样写可以稍微的加快点执行速度 */

queue->elems[queue->tail] = elem;

queue->tail = tail;

}

else /** 此时队列已满 */

{

printf("the queue is full!");

}

出队: 先判断 tail 和head是否相等,如果相等,就比较队列已空,无元素可出,不等则表示非空。此时需要取出head对于位置的元素,然后将head加1(当然,为了能够在head 增加到数组尾部时能够转回到首部,那么这里其实需要 将head加1与队列的size取余再赋值给head),其伪代码如下:

elem_type elem = elem_null; /** 初始化元素 */

if(queue->tail != queue->head) /** 判断队列不为空 */

{/**这样写的作用与上一段伪代码的作用是一样的 */

elem = queue->elems[queue->head];

/** 取余保证,当head= size - 1 时,转回到0 */

queue->head = (queue->head+1) % queue->size;

}

else /** 此时队列已空 */

{

printf("the queue is empty \n");

}

return elem;

三、和盘托出

这里就是我的具体实现。目前我实现的是无限队列(链式队列 ),链表就是前一章实现的list。

其头文件如下:

#ifndef __TINY_QUEUE_H__

#define __TINY_QUEUE_H__

#include "general_type.h"

#ifdef __cplusplus

extern "C" {

#endif

/***************************************************************************

*

* macro declaration

*

***************************************************************************/

/***************************************************************************

*

* data structure declaration

*

***************************************************************************/

/** the callback function for free item */

typedef void (*tfQueueItemFreeFunc_t)(void* item);

/***************************************************************************

*

* API declaration

*

***************************************************************************/

/**

*@brief create a queue instance

*

*@param none

*

*@return success: queue instance handle, fail: NULL.

*@see

*

*/

G_API GPHD tfQueueCreate(void);

/**

*@brief destroy a queue instance

*

*@param queue [in] pointer to queue instance

*

*@return none.

*@see

*

*/

G_API void tfQueueDestroy(GPHD queue);

/**

*@brief clear(remove and free) all item in queue

*

*@param queue [in] pointer to queue instance

*@param item_free [in] callbck function for free item.

*

*@return none.

*@see

*

*/

G_API void tfQueueClear(GPHD queue, tfQueueItemFreeFunc_t item_free);

/**

*@brief append a item to current queue.

*

*@param queue [in] pointer to queue instance

*@param item [in] pointer new item.

*

*@return success: GTRUE, fail: GFALSE

*@see

*

*/

G_API GBOL tfQueueEnQueue(GPHD queue, void* item);

/**

*@brief pop a item from current queue

*

*@param queue [in] pointer to queue instance

*

*@return success: item handle, fail: NULL.

*@see

*

*/

G_API void *tfQueueDeQueue(GPHD queue);

/**

*@brief get the count of item in current queue.

*

*@param queue [in] pointer to queue instance

*

*@return how many item in current queue.

*@see

*

*/

G_API GU32 tfQueueLength(GPHD queue);

#ifdef __cplusplus

}

#endif

#endif //end of __TINY_QUEUE_H__

其源文件如下:

#include

#include "general_macro.h"

#include "tiny_queue.h"

#include "tiny_list.h"

#include "vos_mem.h"

/***************************************************************************

*

* macro declaration

*

***************************************************************************/

#define LOGE printf

#define LOGD printf

#define LOGW printf

/***************************************************************************

*

* data structure declaration

*

***************************************************************************/

/** data structure for item */

typedef struct my_queue_item_s

{

tiny_list_node_t node;

void* data;

}my_queue_item_t;

/** data structure for queue */

typedef struct my_queue_s

{

tiny_list_t items;

}my_queue_t;

/***************************************************************************

*

* inner API define

*

***************************************************************************/

static my_queue_item_t* tqItemNew(void* data)

{

my_queue_item_t* item = (my_queue_item_t*)memAlloc(sizeof(my_queue_item_t));

if (item)

{

item->data = data;

}

return item;

}

/***************************************************************************

*

* API define

*

***************************************************************************/

GPHD tfQueueCreate(void)

{

my_queue_t* mq = (my_queue_t*)memAlloc(sizeof(my_queue_t));

if (mq)

{

memset(mq, 0, sizeof(*mq));

tfListInitialize(&(mq->items), memFree);

}

else

{

LOGE("alloc queue instance failed\n");

}

return mq;

}

void tfQueueDestroy(GPHD queue)

{

if (queue)

{

my_queue_t* mq = (my_queue_t*)queue;

tiny_list_t* tl = &(mq->items);

GU32 left_count = tfListCount(tl);

if (left_count > 0)

{

LOGW("here have: %d items in queue, it's maybe lead to memory leak\n", left_count);

}

tfListClear(tl);

memFree(queue);

}

}

void tfQueueClear(GPHD queue, tfQueueItemFreeFunc_t item_free)

{

if (queue)

{

my_queue_t* mq = (my_queue_t*)queue;

tiny_list_t* tl = &(mq->items);

if (item_free)

{

tiny_list_node_t* node = tfListFront(tl);

while (node)

{

my_queue_item_t* mqi = (my_queue_item_t*)node;

item_free(mqi->data);

node = node->next;

}

}

else

{

LOGW("item_free is NULL, so here wouldn't free item, it maybe lead to memory leak\n");

}

tfListClear(tl);

}

}

GBOL tfQueueEnQueue(GPHD queue, void* item)

{

GBOL ret = GFALSE;

if (queue)

{

my_queue_t* mq = (my_queue_t*)queue;

tiny_list_t* tl = &(mq->items);

my_queue_item_t* mqi = tqItemNew(item);

GCHECK(mqi);

tfListPushBack(tl, (tiny_list_node_t*)mqi);

/** todo, is need check push to list is successed ?? */

ret = GTRUE;

}

return GFALSE;

}

void *tfQueueDeQueue(GPHD queue)

{

void* item = NULL;

if (queue)

{

my_queue_t* mq = (my_queue_t*)queue;

tiny_list_t* tl = &(mq->items);

my_queue_item_t* node = (my_queue_item_t*)tfListFront(tl);

if (node)

{

item = node->data;

tfListPopFront(tl); /** remove head node from list */

}

}

return item;

}

GU32 tfQueueLength(GPHD queue)

{

GU32 ret = 0;

if (queue)

{

my_queue_t* mq = (my_queue_t*)queue;

ret = tfListCount(&(mq->items));

}

return ret;

}

其中的 vos_mem.h是我封装的虚拟系统接口中关于memory操作的部分,以作跨平台使用,以上源文件中使用到的memAlloc,memFree可以简单的理解为标准的malloc和free。general_macro.h可以去看第九章。

四、扪心自问

这里只是实现了无限队列的情况,如果后续在开发的过程中还需要有限队列的话,再添加相关接口与实现代码。

c语言队列原理的实现,c印记(十二):队列queue原理与实现相关推荐

  1. 微型计算机中存储器分成哪几个等级?它们各有什么特点?用途如何?,《微机原理》复习思考题第十二章存储器.DOC...

    <微机原理>复习思考题第十二章存储器 第章 存储器 ?????????????????????????????????????????????????????????? ????????? ...

  2. C语言/C++常见习题问答集锦(五十二) 之职工信息管理系统

    C语言/C++常见习题问答集锦(五十二) 之职工信息管理系统 程序之美 用C语言,职工信息管理系统具体要求 1.基本信息:如工号.姓名.性别.年龄.学历.住址.电话号码.工资等. 2.各职工信息用结构 ...

  3. 【C语言进阶深度学习记录】三十二 函数指针与使用函数指针实现回调函数

    回调函数是非常重要的概念 文章目录 1 函数的类型 2 函数指针 2.1 函数指针的使用 2.2 使用函数指针实现回调函数 3 总结 1 函数的类型 跟以前学数组的时候是一样的,C语言中的数组是有自己 ...

  4. 从C语言的角度重构数据结构系列(十二)-C语言判断语法详解(ifswitch)

    前言 在这里给自己打个广告,需要的小伙伴请自行订阅. python快速学习实战应用系列课程 https://blog.csdn.net/wenyusuran/category_2239261.html ...

  5. 【C语言进阶深度学习记录】三十 二维数组与二维指针

    文章目录 1 二维指针(指向指针的指针) 2 二维数组 3 二维数组的类型 3.2 如何动态申请二维数组 4 总结 1 二维指针(指向指针的指针) 指针的本质是变量 指针的指针是保存指针变量的地址.如 ...

  6. 自动驾驶(五十二)---------惯性导航原理

    惯性导航一般集成在GPS设备中,都是由供应商集成,那在这里有什么讨论的必要呢,要知道在车辆行驶中,我们可以拿到GPS的yawrate和speed信号,而且车辆本身还有一套传感器获取yawrate和sp ...

  7. c语言学习之基础知识点介绍(十二):结构体的介绍

    一.结构体的介绍 /* 语法:struct 结构体名{成员列表;};切记切记有分号!说明:成员列表就是指你要保存哪些类型的数据.注意:上面的语法只是定义一个新的类型,而这个类型叫做结构体类型.因为类型 ...

  8. 20169210《Linux内核原理与分析》第十二周作业

    Return-to-libc 攻击实验 缓冲区溢出的常用攻击方法是用 shellcode 的地址来覆盖漏洞程序的返回地址,使得漏洞程序去执行存放在栈中 shellcode.为了阻止这种类型的攻击,一些 ...

  9. 20169212《Linux内核原理及分析》第十二周作业

    格式化字符串漏洞实验 格式化字符串漏洞是由像 printf(user_input) 这样的代码引起的,其中 user_input 是用户输入的数据,具有 Set-UID root 权限的这类程序在运行 ...

最新文章

  1. 刚刚,2021年诺贝尔生理学或医学奖揭晓!
  2. C# ?(问号)的三个用处
  3. Oracle 11g Dataguard 物理备库配置(四)之broker snapshot standby测试
  4. Django视图(三)
  5. 使用Python计算指定目录md5,根据md5找查到相同的文件并打印
  6. Confluent官博:Kafka最牛队列,性能15倍于RabbitMQ!
  7. linux apf防火墙安装配置
  8. mysql 删除 like_MySQL 定时删除数据
  9. 【Siddhi】Error:osgi: [siddhi-execution-string] Manifest file ${_include} missing OSGi facet
  10. 线上售楼处,卖房神器还是营销噱头?
  11. 韩顺平 php大牛班课程,2016泰牛程序员韩顺平PHP大牛班HTML课程完整笔记资料.doc...
  12. Volatility3 windows插件详解
  13. h3c交换机服务器无响应,华为(H3C)交换机版本升级遇到的问题总结
  14. 51单片机制作简易计算器(动态数码管、矩阵按键)
  15. fastlane实现Android自动化打包
  16. 最新版的sweetalert路径
  17. 计算机表格常用根式,excel怎么建立常用根式_在excel中怎样开根号�9�3
  18. JS和node.js的区别
  19. html5 jquery魔方,基于jquery的魔方插件
  20. 2023年如何做谷歌SEO优化?谷歌优化排名怎么做?

热门文章

  1. 抽象工厂设计模式解释
  2. java.lang.NoClassDefFoundError:如何解决–第3部分
  3. Apache Shiro第1部分–基础
  4. Java EE 6示例– Galleria –第3部分
  5. 使用Spring AOP进行面向方面的编程
  6. Iphone 手机如何导入/导出通讯录
  7. matlab 功率谱密度 汉宁窗_如何理解随机振动的功率谱密度?
  8. 网络位置可以看到另一个人的电脑_计算机组成原理(一)- 冯·诺依曼体系结构...
  9. LeetCode 16.01 交换两数
  10. 接口入口在什么地方_弱电工程施工图审查要点?有哪些地方需要审核?审核要求是什么?...