概念

为了性能考虑,嵌入式系统一般使用C语言进行开发,由于C语言标准库没有封装链表,所以嵌入式系统一般自己设计和实现链表这种数据结构。单链表是链表中的一种,本文描述OpenAtom OpenHarmony(以下简称“OpenHarmony”)中HDF软件模块自己定义的单链表,并学习其设计和实现方法。其中包含一些技巧,可以提高读者的软件开发能力。

单链表定义

在OpenHarmony的HDF软件模块中,单链表定义在hdf_slist.h中。

struct HdfSListNode {
struct HdfSListNode *next; // next element in list, or NULL
};

其示意图如下:

如上图所述,每个节点都是HdfSListNode,上图共有5个节点,每个节点内部有一个next成员,其值为下一个节点在内存中的地址。由于可以通过这个地址找到下一个节点,所以在图里面用红色右箭头来描述这个关系。整体来看,从1号节点可以通过next成员依次找到后面4个节点,从图形看,就是一个逻辑上的链关系,我们把这种结构称为链表。

单独看5号节点,5号节点没有下一个节点,所以设计上是需要给一个特定的值来表示,实现上一般把5号节点的next成员填成0值,表明其为最末尾的节点。

接下来我们看下面这个数据结构:

struct HdfSList {
struct HdfSListNode *root;
};

  

其示意图如下:

如上图所示,圆角矩形表示的是HdfSList,其root成员记录了链表中某节点的地址,为了访问整个链表,需要将root成员的值设置成第1个节点的地址。因为单链表只支持往一个方向查找,不支持往回查找,如上面的错误范例。如果root记录的是第二个节点地址,则第一个节点变得不可访问。

迭代器简介

迭代器是伴随集合概念产生的,意思是依次访问集合中的每一个元素,迭代器提供访问这些元素的方法。对于单链表而言,链表中的每一个节点都是一个元素,所有的节点组成集合。所以可以通过迭代器来访问链表中的元素。

迭代器需要提供的基本能力以及操作范式是:

初始化迭代器
重复判断(集合中还有未被访问的元素)
获取下一个元素的访问方法
读写下一个元素(也可能是删除这个元素)
结束

  

上述范式展示了迭代器的用法,通过迭代器,遍历元素变得简单直接(将遍历算法封装在迭代器中),不用每次迭代都考虑数据结构细节(数据结构种类繁多,单链表只是其中之一)。

对于本文描述的单链表,其封装了下面3个函数来支持迭代算法。这3个函数分别表示迭代器对象的初始化;集合中是否还有元素没有参与迭代;取出集合中下一个可以参与迭代的元素。

/* * @brief initialize iterator * * @param[in] iterator the point of iterator. * @param[in] list the point of operation list. * * @return None */
void HdfSListIteratorInit(struct HdfSListIterator *iterator, struct HdfSList *list); /* * @brief check whether list has next node. * * @param[in] iterator the point of iterator. * * @return the result of check next. */
bool HdfSListIteratorHasNext(struct HdfSListIterator *iterator); /* * @brief get next link in the list and move iterator to next. * * @param[in] iterator the point of iterator. * * @return point to next element of it. */
struct HdfSListNode *HdfSListIteratorNext(struct HdfSListIterator *iterator);

  

迭代器实现考虑

对于本文所描述的单链表迭代器。直观上看,除了第一个节点,其它节点都可以通过next访问到,第一个节点通过root访问到。那实际上会不会就是这么简单呢?其实不然,因为需要考虑到节点删除的因素。如下图,在链表迭代过程中,如果删除了当前节点,那么怎么找到下一个节点呢?

如上图所示,当在遍历过程中删除了curr节点时,那么通过它找到下一个节点是不可能了。所以这个时候我们必须借助操作curr之前还在链表上的上一个节点,即上图的prev节点,通过其next成员,找到需要迭代处理的下一个节点。所以,迭代过程中需要记录prev、curr这2个节点的位置信息。迭代过程实际就是调整prev和curr的过程,对于不删除的情况,prev和curr依次向后移动,删除操作时,只移动curr。

另外,对于第1个节点的情况需要特殊处理,所以需要一个额外的信息来表示是不是迭代第1个元素,因为本文描述的迭代器对象含有3个信息。如下代码所示:

struct HdfSListIterator {
int stepOnNext; //是否即将开始遍历第二个以及之后的元素
struct HdfSListNode *prev; // points to the item before the current one 当前被操作元素的前一个元素
struct HdfSListNode *curr; // points to the current item (to detect item removal) 当前被操作的元素,可能刚操作完,被移除链表
};

  

上述代码中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

OpenHarmony中的HDF单链表及其迭代器的更多相关文章

  1. python中栈的单链表实现

    参考博客:https://www.cnblogs.com/stacklike/p/8284550.html 基于列表的简单实现 # 先进后出 # 以列表实现的简单栈 class SimpleStack ...

  2. C#中泛型和单链表

      泛型是 2.0 版 C# 语言和公共语言运行库 (CLR) 中的一个新功能.泛型将类型参数的概念引入 .NET Framework,类型参数使得设计如下类和方法成为可能:这些类和方法将一个或多个类 ...

  3. 单链表的C++实现(采用模板类)

    采用模板类实现的好处是,不用拘泥于特定的数据类型.就像活字印刷术,制定好模板,就可以批量印刷,比手抄要强多少倍! 此处不具体介绍泛型编程,还是着重叙述链表的定义和相关操作.  链表结构定义 定义单链表 ...

  4. 用Java实现单链表的基本操作

    笔试题中经常遇到单链表的考题,下面用java总结一下单链表的基本操作,包括添加删除节点,以及链表转置. package mars; //单链表添加,删除节点 public class ListNode ...

  5. java单链表常用操作

    总结提高,与君共勉 概述. 数据结构与算法亘古不变的主题,链表也是面试常考的问题,特别是手写代码常常出现,将从以下方面做个小结 [链表个数] [反转链表-循环] [反转链表-递归] [查找链表倒数第K ...

  6. 数据结构(2):单链表学习使用java实现

    单链表是单向链表,它指向一个位置: 单链表常用使用场景:根据序号排序,然后存储起来. 代码Demo: package com.Exercise.DataStructure_Algorithm.Sing ...

  7. JAVA实现具有迭代器的线性表(单链表)

    一,迭代器的基本知识: 1,为什么要用迭代器?(迭代:即对每一个元素进行一次“问候”) 比如说,我们定义了一个ADT(抽象数据类型),作为ADT的一种实现,如单链表.而单链表的基本操作中,大部分需要用 ...

  8. [LeetCode] Linked List Cycle II 单链表中的环之二

    Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Foll ...

  9. [算法][LeetCode]Linked List Cycle & Linked List Cycle II——单链表中的环

    题目要求 Linked List Cycle Given a linked list, determine if it has a cycle in it. Follow up: Can you so ...

  10. [CareerCup] 2.6 Linked List Cycle 单链表中的环

    2.6 Given a circular linked list, implement an algorithm which returns the node at the beginning of ...

随机推荐

  1. yolov5项目cuda错误解决

    CUDA报错解决 # 报错详情 AssertionError: CUDA unavailable, invalid device 0 requested 查看cuda版本 先看一下电脑是否支持GPU, ...

  2. 【LeetCode二叉树#16】二叉(搜索)树的最近公共祖先(递归后序遍历,巩固回溯机制)

    二叉树的最近公共祖先 力扣题目链接(opens new window) 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先. 百度百科中最近公共祖先的定义为:"对于有根树 T 的两个结点 ...

  3. 浅入Kubernetes(9):了解组件

    本篇主要介绍 Kubernetes 中的架构组成,在前面我们已经学习到了 kubeadm.kubectl,这两个命令行工具是 k8s 组成之一.而前面在搭建集群时,也学到了 master.worker ...

  4. 一文了解 Nebula Graph DBaaS 服务——Nebula Graph Cloud Service

    Nebula Graph DBaaS 作为一款 DBaaS(DataBase as s Service)的产品,Nebula Graph Cloud Service 极大地降低了研发人员使用 Nebu ...

  5. Java 多线程------解决 实现继承 Thread类 方式线程的线程安全问题 方式二:同步方法

    1 package bytezero.threadsynchronization; 2 3 4 5 /** 6 * 使用同步方法解决实现 继承 Thread类 的线程安全问题 7 * 8 * 9 * ...

  6. Java 类方法的声明和使用

    1 /** 2 * 3 * @Description 4 * @author Bytezero·zhenglei! Email:420498246@qq.com 5 * @version 6 * @d ...

  7. 出海业务如何搭建国内也能快速访问的https网站与接口(无需备案)

    背景信息 由于最近在搭建我的出海网站 https://www.idatariver.com/zh-cn , 感兴趣的可以看看. 其中一个环节便是给后端API接口加上ssl,毕竟http看着不如http ...

  8. Ubuntu18.04声卡配置问题解决

    一 问题 对于经常做音频的工程师来说,经常需要使用linux下的声卡切换,期间遇到了各种问题,自使用了pavucontrol,问题没有了.真是瞬间感觉赏心悦目啊. 二 安装使用方法 安装pavucon ...

  9. Linux int型转换为char*型几种方法总结

    一 前记 这种转换,windows下最常用就是atoi()函数.可惜的是,在Linux中没有itoa()函数,只有atoi()   这点很有趣,居然不对称. 所以在Linux中实现从整型到char*的 ...

  10. python删除指定文件夹下文件和文件夹的方法

    前记   python删除指定文件夹下的文件,是一个常用的功能.我找了不少地方,一直没有找到合适的模版,那只好自己倒腾一个比较实用的模版了. 基本模块   这里面会用到几个模块,一个是目录下所有文件的 ...