OpenHarmony 中的 HDF 单链表及其迭代器
概念
为了性能考虑,嵌入式系统一般使用 C 语言进行开发,由于 C 语言标准库没有封装链表,所以嵌入式系统一般自己设计和实现链表这种数据结构。单链表是链表中的一种,本文描述 OpenAtom OpenHarmony(以下简称“OpenHarmony”)中 HDF 软件模块自己定义的单链表,并学习其设计和实现方法。其中包含一些技巧,可以提高读者的软件开发能力。
单链表定义
在 OpenHarmony 的 HDF 软件模块中,单链表定义在 hdf_slist.h 中。
如上图所述,每个节点都是 HdfSListNode,上图共有 5 个节点,每个节点内部有一个 next 成员,其值为下一个节点在内存中的地址。由于可以通过这个地址找到下一个节点,所以在图里面用红色右箭头来描述这个关系。整体来看,从 1 号节点可以通过 next 成员依次找到后面 4 个节点,从图形看,就是一个逻辑上的链关系,我们把这种结构称为链表。
单独看 5 号节点,5 号节点没有下一个节点,所以设计上是需要给一个特定的值来表示,实现上一般把 5 号节点的 next 成员填成 0 值,表明其为最末尾的节点。
接下来我们看下面这个数据结构:
其示意图如下:
如上图所示,圆角矩形表示的是 HdfSList,其 root 成员记录了链表中某节点的地址,为了访问整个链表,需要将 root 成员的值设置成第 1 个节点的地址。因为单链表只支持往一个方向查找,不支持往回查找,如上面的错误范例。如果 root 记录的是第二个节点地址,则第一个节点变得不可访问。
迭代器简介
迭代器是伴随集合概念产生的,意思是依次访问集合中的每一个元素,迭代器提供访问这些元素的方法。对于单链表而言,链表中的每一个节点都是一个元素,所有的节点组成集合。所以可以通过迭代器来访问链表中的元素。
迭代器需要提供的基本能力以及操作范式是:
上述范式展示了迭代器的用法,通过迭代器,遍历元素变得简单直接(将遍历算法封装在迭代器中),不用每次迭代都考虑数据结构细节(数据结构种类繁多,单链表只是其中之一)。
对于本文描述的单链表,其封装了下面 3 个函数来支持迭代算法。这 3 个函数分别表示迭代器对象的初始化;集合中是否还有元素没有参与迭代;取出集合中下一个可以参与迭代的元素。
迭代器实现考虑
对于本文所描述的单链表迭代器。直观上看,除了第一个节点,其它节点都可以通过 next 访问到,第一个节点通过 root 访问到。那实际上会不会就是这么简单呢?其实不然,因为需要考虑到节点删除的因素。如下图,在链表迭代过程中,如果删除了当前节点,那么怎么找到下一个节点呢?
如上图所示,当在遍历过程中删除了 curr 节点时,那么通过它找到下一个节点是不可能了。所以这个时候我们必须借助操作 curr 之前还在链表上的上一个节点,即上图的 prev 节点,通过其 next 成员,找到需要迭代处理的下一个节点。所以,迭代过程中需要记录 prev、curr 这 2 个节点的位置信息。迭代过程实际就是调整 prev 和 curr 的过程,对于不删除的情况,prev 和 curr 依次向后移动,删除操作时,只移动 curr。
另外,对于第 1 个节点的情况需要特殊处理,所以需要一个额外的信息来表示是不是迭代第 1 个元素,因为本文描述的迭代器对象含有 3 个信息。如下代码所示:
上述代码中 prev 和 curr 的作用已经在前面详细描述,而 stepOnNext 的意思就是是否已经开始取第二个元素。即将第一个元素的获取算法与第二个元素分开。
结论
在嵌入式开发中,在学习数据结构课程中,在进行 OpenHarmony 项目开发中,单链表都是很重要的,而本文只是其中一个软件模块的单链表实现。通过对单链表的实现的图示分析,特别是迭代器惯用法的分析,相信读者对单链表以及迭代器的认识都会进一步提升,更详尽的代码分析和阅读留给读者自己进行,请参考如下代码文件:
https://gitee.com/openharmony/drivers_hdf_core/blob/master/framework/utils/include/hdf_slist.h
https://gitee.com/openharmony/drivers_hdf_core/blob/master/framework/utils/src/hdf_slist.c
评论