vxworks中使用了多种基本数据结构,例如双向链表,队列,树等等,本文将介绍这些基本数据结构在vxworks中的实现。

1. 双向链表

双向链表是最简单的数据结构,其实现也非常简单;而且,双向链表往往是实现其他数据结构的基础,因此本文最先介绍双向链表。双向链表的定义在dllLib.h文件中,函数实现在dllLib.c文件中。

在介绍双向链表之前,有必要先介绍一下vxworks中双向链表的实现样式:

List为一个指针,该指针链表结构体,包含两个域,分别指向链表头节点和尾节点:

typedef struct   
    {
    DL_NODE *head; 
    DL_NODE *tail; 
    } DL_LIST;

head和tail指针分别指向链表的头节点和尾节点,节点结构体包含两个域,分别为前一个节点和后一个节点,节点结构体的定义为:

typedef struct dlnode  
    {
    struct dlnode *next; 
    struct dlnode *previous; 
    } DL_NODE;

1.1 双向链表创建

在创建链表时,链表还没有任何子节点,因此此时的头节点和尾节点指针均为NULL;但是链表结构体需要创建,因此需要为链表结构体分配内存,创建链表代码如下:

DL_LIST *dllCreate (void)
    {
    FAST DL_LIST *pList = (DL_LIST *) malloc ((unsigned) sizeof (DL_LIST));

dllInit (pList);

return (pList);
    }

STATUS dllInit
    (
    FAST DL_LIST *pList     /* #define FAST register */
    )
    {
    pList->head  = NULL;
    pList->tail  = NULL;

return (OK);
    }

此时创建的链表结构只有一个链表头,但是还没有任何节点:

1.2 添加节点

vxworks中的双向链表的节点都是添加在链表的尾部,通过的dllAdd函数实现,而dllAdd函数通过调用dllInsert函数来实现,dllInsert函数实现具体的添加过程;链表节点的添加主要通过一些指针的迁移来完成,在添加过程中需要注意中间节点的存储,并注意指针迁移顺序,最重要的是千万要保证链表不能断链,说了这么多,不如看代码实在:

void dllAdd
    (
    DL_LIST *pList,     /* pointer to list descriptor */
    DL_NODE *pNode      /* pointer to node to be added */
    )
    {
    dllInsert (pList, pList->tail, pNode);
    }

void dllInsert
    (
    FAST DL_LIST *pList,        /* pointer to list descriptor */
    FAST DL_NODE *pPrev,        /* pointer to node after which to insert */
    FAST DL_NODE *pNode         /* pointer to node to be inserted */
    )
    {
    FAST DL_NODE *pNext;

if (pPrev == NULL)
 {    /* new node is to be first in list */
 pNext = pList->head;                                  
 pList->head = pNode;                                       /*1.设置链表结构体的头指针*/
 }
    else
 {    /* make prev node point fwd to new */
 pNext = pPrev->next;
 pPrev->next = pNode;                                     /*2.将节点添加到添加处节点的后面*/

}

if (pNext == NULL)
 pList->tail = pNode;                                    /*3.设置链表结构体的尾指针*/ 
    else
 pNext->previous = pNode;                          /*4.将节点添加到添加处节点的后面节点的前面*/

/* set pointers in new node */

pNode->next  = pNext;                                            /*5.设置节点的后向指针*/
    pNode->previous = pPrev;                                           /*6.设置节点的前向指针*/
    }

双向链表的添加,需要分三种情况:

1.2.1 链表中无节点

链表刚创建时就是类似的情况,此时链表结构体的头指针和尾指针均指向NULL;这种情况下添加节点主要是执行代码中的1、3、5、6语句,可以用下图表示:

1.2.2 链表中有1个节点

当链表中有1个节点时,链表结构体的头指针和尾指针均指向该节点,但是该节点的前向和后向指针则为NULL,此时添加节点主要执行代码中的2、3、5、6语句,具体操作可以用下图演示:

1.2.3 链表中节点个数大于1个

如果链表中的节点个数大于1个的时候,就可以在这两个节点中间插入节点了,不过采用dllAdd函数是无法实现的,因为这个函数每次都是在链表的最后一个节点处添加节点的,因此执行的语句仍然是2、3、5、6,和前面一种情况是一样的;要实现往两个节点中间插入节点,只能通过dllInsert函数来实现,这种方式插入节点不需要改变链表结构体的头指针和尾指针,只需要改变节点的前向和后向指针就可以了,执行的语句为2、4、5、6,可以用下图来演示:

1.2.4 在链表头部添加节点

当链表中没有节点时,在链表头部添加节点和第一种情况是完全一样的,执行1、3、5、6语句;如果链表中有节点时,需要改变链表头指针的位置,执行的语句为1、4、5、6,具体情况和上面大同小异:

1.3 删除节点

节点的删除相对于节点的添加来说,要相对容易一些,因为节点的删除只需要改变两个指针即可;不过和添加节点相同的是,删除节点也需要考虑四种情况,具体代码如下:

void dllRemove
    (
    DL_LIST *pList,             /* pointer to list descriptor */
    DL_NODE *pNode              /* pointer to node to be deleted */
    )
    {
    if (pNode->previous == NULL)
 pList->head = pNode->next;                                        /*1.改变链表的头指针*/
    else
 pNode->previous->next = pNode->next;                     /*2.改变待删除节点的前向节点的后向指针*/

if (pNode->next == NULL)
 pList->tail = pNode->previous;                                   /*3.改变链表的尾指针*/
    else
 pNode->next->previous = pNode->previous;              /*4.改变待删除节点的后向节点的前向指针*/
    }

1.3.1 删除节点为链表中唯一的一个节点

此时链表中的节点既是链表的第一个节点,也是最后一个节点,因此,删除该节点后,链表中没有节点,链表的头指针和尾指针均为NULL;此种情况下,执行的语句为1、3,具体演示如下:

1.3.2 链表中节点数大于1个,删除节点为链表的第一个节点

删除节点为链表的第一个节点,链表的尾指针将不会发生变化,头指针指向待删除节点的下一个节点,而待删除节点的后向节点的前向指针将为NULL,执行语句为1、4,具体演示如下:

1.3.3 链表中节点数大于1个,删除节点为链表的最后一个节点

删除节点为链表的最后一个节点,链表的头指针不会发生变化,尾指针指向待删除节点的前向节点,而待删除节点的前向节点的后向指针将为NULL,执行语句为2、3,具体演示如下:

1.3.4 链表中节点数大于2个,删除节点为链表中间的一个节点

此种情况最简单,只需要改变待删除节点的前向节点的后向指针和后向节点的前向指针,将待删除节点的前向节点和后向节点连接起来即可,执行语句为2、4,具体演示如下:

1.4 获取首节点

获取首节点通过dllGet函数实现,主要完成两个功能:删除首节点,返回首节点;删除首节点和删除节点功能基本相似,主要是前面描述的1.3.1和1.3.2描述的情况,至于返回首节点就更加简单了:

DL_NODE *dllGet
    (
    FAST DL_LIST *pList         /* pointer to list from which to get node */
    )
    {
    FAST DL_NODE *pNode = pList->head;

if (pNode != NULL)                      /* is list empty? */
 {
        pList->head = pNode->next;          /* make next node be 1st */

if (pNode->next == NULL)            /* is there any next node? */
            pList->tail = NULL;             /*   no - list is empty */
        else
            pNode->next->previous = NULL;   /*   yes - make it 1st node */
 }

return (pNode);
    }

1.5 获取节点数目

获取节点数目通过dllCount函数实现,并结合DLL_NEXT宏实现,DLL_NEXT定义如下:

#define DLL_NEXT(pNode)   \
    (     \
    (((DL_NODE *)(pNode))->next) \
    )
dllCount函数实现如下:

int dllCount
    (
    DL_LIST *pList      /* pointer to list descriptor */
    )
    {
    FAST DL_NODE *pNode = DLL_FIRST (pList);
    FAST int count = 0;

while (pNode != NULL)
 {
 count++;
 pNode = DLL_NEXT (pNode);
 }

return (count);
    }

1.6 遍历节点

节点遍历和返回节点数目函数类似,不再多述。

1.7 删除链表

删除链表和创建链表相对应,主要是释放内存:

STATUS dllDelete
    (
    DL_LIST *pList     /* pointer to list head to be initialized */
    )
    {
    free ((char *) pList);   /* free list */
    return OK;
    }

函数内容十分简单,不过个人对此有些异议,总觉得应该先判断链表中是否有节点,如果有节点应该先删除节点并且释放掉节点内存后当链表中没有节点了才能删除链表,否则有些节点可能就成为野节点了,无法访问,但也无法释放了。不过vxworks这样写,应该有它自己的道理,毕竟我也只是看了一小部分代码,等全部看完了,应该能回答这个问题。

vxworks源码剖析- 数据结构篇一(双向链表)-转相关推荐

  1. pymavlink 源码剖析(一)之XML文件的数据解析

    文章目录 1 引言 2 pymavlink 的代码自动生成方法 3 XML 文件的数据解析 3.1 XML 文件预处理 3.2 解析 XML 的数据 3.2.1 依据协议版本初始化一些版本特征变量 3 ...

  2. python源码剖析 豆瓣_在数据分析师的分析中豆瓣的书那些值得读

    最近总是有人问我有什么书好推荐看看,特烦.但是看到那么多人问,看来挺多人有这个需求,便想了一下,如何通过数据分析找到值得看的书.通过爬取某个标签例如产品,运营获取对应已经打了标签的书,获取书对应的评分 ...

  3. LinkedList源码剖析

    1. LinkedList简介 LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当作链表来操作外,它还可以当作栈,队列和双端队列来使用. LinkedList同样是非线 ...

  4. LinkedHashMap源码剖析

    1. LinkedHashMap简介 LinkedHashMap是HashMap的子类,与HashMap有着同样的存储结构,但它加入了一个双向链表的头结点,将所有put到LinkedHashmap的节 ...

  5. STL源码剖析---list

    相较于vector的连续线性空间,list就显得复杂许多,它的好处是每次插入或删除一个元素,就配置或释放一个元素空间.因此,list对于空间的运用有绝对的精准,一点也不浪费.而且,对于任何位置的元素插 ...

  6. 转:【Java集合源码剖析】LinkedHashmap源码剖析

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/37867985   前言:有网友建议分析下LinkedHashMap的源码,于是花了一晚上时 ...

  7. ConcurrentHashMap源码剖析(1.8版本)

    目录 ConcurrentHashMap源码剖析 数据结构 Node ForwardingNode TreeNode TreeBin 核心成员 核心函数 ConcurrentHashMap(int i ...

  8. 【Redis源码剖析】 - Redis内置数据结构之压缩列表ziplist

    在前面的一篇文章[Redis源码剖析] - Redis内置数据结构之双向链表中,我们介绍了Redis封装的一种"传统"双向链表list,分别使用prev.next指针来指向当前节点 ...

  9. C++ STL源码剖析 笔记

    写在前面 记录一下<C++ STL源码剖析>中的要点. 一.STL六大组件 容器(container): 各种数据结构,用于存放数据: class template 类泛型: 如vecto ...

最新文章

  1. css毛玻璃效果白边_CSS3毛玻璃效果(blur)有白边问题的解决方法
  2. C#中实现对Excel特定文本的搜索
  3. 《数字图像处理与机器视觉——Visual C++与Matlab实现(第2版)》——1.2 数字图像处理与机器视觉...
  4. 从postgress 读取数据
  5. WebAssembly + Dapr = 下一代云原生运行时?
  6. 【Android】可以下拉刷新的webview,使你的webview效果更加好看,封装自己的WebView...
  7. Ajax — 评论列表
  8. Python hash、xml、configparser、sheve、shutil模块讲解 以及 面向对象初识
  9. .net core精彩实例分享 -- 依赖注入和中间件
  10. 适用于树莓派Raspberry Pi的嵌入式QT平台(二) -- 在Windows下用Qt Creator开发编译Raspberry Qt 5应用程序...
  11. 重磅:IntelliJ IDEA 2020.2 EAP 5 已发布,可完美支持Java 15
  12. 小客车年检(年审)相关的技术参数一览
  13. 【Tools】OBS Studio录制视频教程
  14. android圆形图片裁剪demo以及实现
  15. 从来没有一种工作叫钱多、事少、离家近
  16. python testng_自动化测试框架TestNG
  17. 2022-2028全球与中国呼吸系统疾病治疗市场现状及未来发展趋势
  18. python制作聊天机器人_如何制作一个聊天机器人?
  19. Arduino控制舵机详解(含代码)
  20. mysql删库命令是啥_删除数据库的命令是什么

热门文章

  1. 易语言mysql清空一个表_易语言高级表格清空.doc
  2. android对象关系映射框架ormlite之一对多(OneToMany)
  3. AndroidTestCase常用的两段配置
  4. cts测试之CertificateTest
  5. WordPress 5.0禁用古滕堡编辑器的方法
  6. Hexo多客户端同步问题
  7. Linux用户管理(六)Linux磁盘管理
  8. Bootstrap学习(一):Bootstrap简介
  9. 经典算法面试题目-翻转一个C风格的字符串(1.2)
  10. js中的 substring和substr方法