hlist(哈希链表)可以通过相应的Hash算法,迅速找到相关的链表Head及节点.

在有些应用场景,比Go标准库提供的list(一种双向链表)更合适。

依照list.h中的源码,我实现了一个Go语言版本的hlist例子。

首先说下hlist的构成:

在hlist(哈希链表)中,

头结点使用struct hlist_head来表示,hlist_head仅一个first指针.

普通节点使用struct hlist_node来表示。

源码中有几个特别的地方:

1. 在struct hlist_node中有一个**pprev中的二级指针,

pprev指向的是当前hlist_node变量中的前一个变量的next的地址,

如果是第一个元素的话,这个值指向的是first的地址,

如果是最后一个节点的话,指向的是NULL。

2.container_of

源码里面有个宏定义:

#define hlist_entry(ptr, type, member) container_of(ptr,type,member)

利用一些技巧,可通过结构体内部成员member(即链表node)得到所在结构体的首地址

所以C/C++应用中调用时,常用如下定义方式:

struct MYST {

int data;

struct list_head  head;

struct hlist_node node;

} *myst;

在Go中,我将其变更为:

type HLElement struct {

Next  *HLElement

PPrev **HLElement

Value interface{}

}

利用interface{}的特性,可将自定义struct之类对应设置给Value.在使用时,通过interface{}

转换回原本对象即可

3.在hlist_del()中使用LIST_POISON而不是(== NULL)的形式

n->next = LIST_POISON1;

n->pprev = LIST_POISON2;

原因可能是,通过这个标记删除node,如果在其它地方用到这种node,

可以用来区分是否引用了已被删除的node。

在我这是个可有可无的特性,只需在应用时,注意一下即可。

所以在Go版中,我直接去掉了LIST_POISON,直接将其设为nil。

4.在遍历链表时,提供了safe版本,防止因为节点被删除而引起的中断

在Go版中我也提供了相关实现。

具体的实现及测试代码:

package main

//hlist (仿Linux内核数据结构hlist, 可参考内核源码list.h)

//author: Xiong Chuan Liang

//date: 2015-2-12

import (

"fmt"

)

func main() {

/*

Hash桶

HLHead[0]

HLHead[1]-> HLElement[0] ->HLElement[1]

HLHead[2]-> HLElement[0]

HLHead[3]-> HLElement[0] ->HLElement[1]-> HLElement[2] ->HLElement[3]

HLHead[4]-> HLElement[0]

*/

fmt.Println(" \n ")

fmt.Println(" hlist用法演示 : ")

lst := [20]HLHead{}

for i := 0; i < 20; i++ {

hash := getHash(i)

elem1 := &HLElement{Value: i}

AddHead(elem1, &lst[hash])

fmt.Println("i:", i, " Hash:", hash)

}

fmt.Println(" \n 遍历其中一个Head(lst[1])所对应的链表: ")

f := func(e *HLElement) bool {

fmt.Println("HLElement.Value =", e.Value)

return true

}

For_each_safe(&lst[1], f)

fmt.Println(" \n ")

fmt.Println(" 演示InsertAfter/InsertBefore : ")

hHead := &HLHead{}

elem1 := &HLElement{Value: 1}

elem2 := &HLElement{Value: 2}

elem3 := &HLElement{Value: 300}

elem4 := &HLElement{Value: 400}

AddHead(elem1, hHead)

InsertAfter(elem1, elem2)

InsertAfter(elem2, elem3)

InsertBefore(elem4, elem3)

fmt.Println(" \n 遍历链表看效果: ")

For_each(hHead, f)

fmt.Println(" \n ")

fmt.Println(" \n 测试MoveList: lst[1] => MoveList(0->1) ")

MoveList(&lst[0], &lst[1])

For_each_safe(&lst[1], f)

fmt.Println(" \n ")

fmt.Println(" 从指定element开始遍历链表: ")

For_each_safe_from(elem2, f)

fmt.Println(" \n ")

fmt.Println(" 将自定义结构体放入链表: ")

elemA := &HLElement{Value: &Demo{"a"}}

elemB := &HLElement{Value: &Demo{"b"}}

elemC := &HLElement{Value: &Demo{"c"}}

AddHead(elemA, hHead)

AddHead(elemB, hHead)

AddHead(elemC, hHead)

fs := func(e *HLElement) bool {

m, ok := e.Value.(*Demo)

if ok {

fmt.Println("struct =", m.Data)

} else {

fmt.Println("int =", e.Value)

}

return true

}

For_each_safe(hHead, fs)

fmt.Println(" \n ")

fmt.Println(" Remove(elemB): ")

Remove(elemB)

For_each_safe(hHead, fs)

fmt.Println(" \n ")

fmt.Println(" Empty()/Unhashed(): ")

if Empty(hHead) {

fmt.Println(" Empty(hHead) = true: hHead对应的链表为空! ")

} else {

fmt.Println(" Empty(hHead) = false: hHead对应的链表不为空! ")

}

hHeadEmpty := &HLHead{}

if Empty(hHeadEmpty) {

fmt.Println(" Empty(hHeadEmpty) = true: hHeadEmpty对应的链表为空! ")

} else {

fmt.Println(" Empty(hHeadEmpty) = false : hHeadEmpty对应的链表不为空! ")

}

if Unhashed(elem1) {

fmt.Println(" Unhashed(elem1) = true: elem1不在链表中! ")

} else {

fmt.Println(" Unhashed(elem1) = false: elem1在链表中! ")

}

}

//演示用的Struct

type Demo struct {

Data string

}

//演示用的Hash算法

func getHash(c int) int {

return (c % 16)

}

///

type HLHead struct {

First *HLElement

}

type HLElement struct {

Next *HLElement

PPrev **HLElement

Value interface{}

}

type ElemFunc func(e *HLElement) bool

func For_each(h *HLHead, f ElemFunc) {

pos := h.First

for pos != nil {

if !f(pos) {

break

}

pos = pos.Next

}

}

func For_each_safe(h *HLHead, f ElemFunc) {

pos := h.First

for pos != nil {

n := pos.Next

if !f(pos) {

break

}

pos = n

}

}

func For_each_safe_from(h *HLElement, f ElemFunc) {

pos := h.Next

for pos != nil {

n := pos.Next

if !f(pos) {

break

}

pos = n

}

}

//将普通结点n插入到头结点h对应的hash桶的第一个结点的位置

func AddHead(n *HLElement, h *HLHead) {

first := h.First

n.Next = first

if first != nil {

first.PPrev = &n.Next

}

h.First = n

n.PPrev = &h.First

}

//n: 新节点, next:链表

func InsertBefore(n *HLElement, next *HLElement) {

pprev := next.PPrev

n.PPrev = pprev

n.Next = next

next.PPrev = &n.Next

if pprev != nil {

//将原来上一个结点的next的值,指向新节点n

*pprev = n

}

}

//n: 链表, next:新节点

func InsertAfter(n *HLElement, next *HLElement) {

next.Next = n.Next

n.Next = next

next.PPrev = &n.Next

if next.Next != nil {

next.Next.PPrev = &next.Next

}

}

//移动list

func MoveList(old, new *HLHead) {

new.First = old.First

if new.First != nil {

//链表所指定向的第一个元素不为空,更改其pprev指向到New

new.First.PPrev = &new.First

}

old.First = nil

}

//判断结点是否已经在链表中,如返回true,表示不在其中

func Unhashed(h *HLElement) bool {

return (h.PPrev == nil)

}

//判断链表是否为空

func Empty(h *HLHead) bool {

return (h.First == nil)

}

//删除节点

func Remove(n *HLElement) {

next := n.Next

pprev := n.PPrev

if pprev != nil {

*pprev = next

}

if next != nil {

next.PPrev = pprev

}

n.Next = nil

n.PPrev = nil

}

///

/*

hlist用法演示 :

i: 0 Hash: 0

i: 1 Hash: 1

i: 2 Hash: 2

i: 3 Hash: 3

i: 4 Hash: 4

i: 5 Hash: 5

i: 6 Hash: 6

i: 7 Hash: 7

i: 8 Hash: 8

i: 9 Hash: 9

i: 10 Hash: 10

i: 11 Hash: 11

i: 12 Hash: 12

i: 13 Hash: 13

i: 14 Hash: 14

i: 15 Hash: 15

i: 16 Hash: 0

i: 17 Hash: 1

i: 18 Hash: 2

i: 19 Hash: 3

遍历其中一个Head(lst[1])所对应的链表:

HLElement.Value = 17

HLElement.Value = 1

演示InsertAfter/InsertBefore :

遍历链表看效果:

HLElement.Value = 1

HLElement.Value = 2

HLElement.Value = 400

HLElement.Value = 300

测试MoveList: lst[1] => MoveList(0->1)

HLElement.Value = 16

HLElement.Value = 0

从指定element开始遍历链表:

HLElement.Value = 400

HLElement.Value = 300

将自定义结构体放入链表:

struct = c

struct = b

struct = a

int = 1

int = 2

int = 400

int = 300

Remove(elemB):

struct = c

struct = a

int = 1

int = 2

int = 400

int = 300

Empty()/Unhashed():

Empty(hHead) = false: hHead对应的链表不为空!

Empty(hHeadEmpty) = true: hHeadEmpty对应的链表为空!

Unhashed(elem1) = false: elem1在链表中!

*/

例子基本实现了常用的东西,实现时主要是要注意下Golang的特性及与C的一些差异。

部份参考资料:

BLOG: http://blog.csdn.net/xcl168

原文:http://blog.csdn.net/xcl168/article/details/43760173

go移植linux内核书名叫啥,Go语言移植Linux内核数据结构hlist相关推荐

  1. go移植linux内核书名叫啥,嵌入式 Linux根文件系统移植之Linux文件系统简介-Go语言中文社区...

    学号:16020311003    姓名:杨虎成 [嵌牛导读]Linux支持多种文件系统,文件系统接口实现为分层的体系结构,将用户接口层.文件系统实现和操作存储设备的驱动程序分隔开 [嵌牛鼻子]Lin ...

  2. linux添加音乐的代码,C语言实现linux系统下的MP3播放器源代码

    [实例简介] 能识别本地的MP3歌曲文件,能根据路径添加入播放器中. 能识别本地的播放列表信息. 具有播放列表功能,能根据用户的需求随意创建.删除播放列表. 用户能往指定的播放列表中添加.删除 ...

  3. linux c实现函数回调,c语言实现linux抓包

    验证安装libpca 引用pcap.h,确认是否能正常用libpcap开发 #include #include int main(int argc, char *argv[]) { char *dev ...

  4. linux终端输出c语言程序,Linux终端程序用c语言实现改变输出的字的颜色

    颜色代码: 格式: echo "\033[字背景颜色;字体颜色m字符串\033[0m" 例如: echo "\033[41;36m something here \033 ...

  5. vss2010c语言怎么运行,在Linux下使用gcc运行C语言程序

    Linux下使用最广泛的C/C++编译器是GCC,大多数的Linux发行版本都默认安装,不管是开发人员还是初学者,一般都将GCC作为Linux下首选的编译工具.本教程毫不犹豫地使用GCC来编译C程序. ...

  6. linux内核深度解析_十年磨一剑,第一本龙芯平台的Linux内核书来了

    <用"芯"探核:基于龙芯的Linux内核探索解析>是一本基于龙芯平台,结合源代码来探索和解析Linux-5.x内核的书. 市面上解析Linux 内核的经典书籍已有不少, ...

  7. 为信息产业自主化而奋斗,第一本龙芯平台的Linux内核书来了!

    十年磨一剑,第一本龙芯平台的Linux内核书来了! 这就是<用"芯"探核:基于龙芯的Linux内核探索解析>--一本基于龙芯平台,结合源代码来探索和解析Linux-5. ...

  8. Linux内核移植漫谈——你不是第一个想移植Linux内核的人

    Jack:在读大学的时候我想过移植Linux操作系统. 我:现在呢? Jack:我还是想移植Linux操作系统.你教我移植吧. 我:你知道什么是"Linux内核移植"吗? Jack ...

  9. 【正点原子Linux连载】第三十七章 Linux内核移植 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

最新文章

  1. canvas——橡皮筋式线条绘图应用
  2. android c 电话联系人,Android 联系人按中文拼音排序
  3. 北斗导航 | 基于卡尔曼滤波的IMU+GNSS的组合导航(附Matlab源代码)
  4. 运维常说的 5个9、4个9、3个9 的可靠性,到底是什么???
  5. 云计算相关资料/博客/网上收集的关于OpenStack的一些资源
  6. 杭州企业“被参与”互联网攻击致半个美国网络瘫痪
  7. 程序员过关斩将--应对高并发系统有没有通用的解决方案呢?
  8. 飞行模式的开启和关闭
  9. 计算机网络之物理层:6、传输介质
  10. 笨办法学 Linux 中文版 翻译完成
  11. Java杂记3—流程控制之条件 1
  12. 部署git服务器(Windows Server 2008)
  13. 图解安装simsun字体后OO乱码的摸黑解决办法【转贴自http://linux.hiweed.com】
  14. 高尚品质_心理学家:品德高尚的人一定具有这6点特征
  15. 小学计算机教师应聘简历,应聘小学教师的个人简历模板
  16. CAD之设置坐标原点
  17. 智能垃圾桶语音芯片应用设计方案介绍,WT588F02B-8S
  18. [hitroad杂货铺]KaTeX使用
  19. 【Angular】angular环境搭建
  20. oracle数据库恢复aul_AUL/MyDUL 非常规灾难恢复ORACLE数据

热门文章

  1. 2017年8月Science肠道菌群研究
  2. pandas使用isna函数和any函数检查dataframe是否包含缺失值、整体是否有缺失值,不区分行列(check if dataframe contains any missing values
  3. R语言ggplot2可视化强制所有的X数值都显示在X轴标签上:x-axis labels with all x-axis values
  4. R语言广义加性模型(generalized additive models,GAMs):使用广义线性加性模型GAMs构建logistic回归
  5. Python以表格、可视化图像的形式输出模型特征重要度(feature importances)并进行重要度归一化及排序
  6. R语言读取excel文件实战(read.xlsx函数、read_excel函数、read.xlsx函数、Write函数)
  7. 使用python包faker生成仿真数据
  8. pdb+ipdb 调试 Python代码
  9. sklearn MLP(多层感知机、Multi-layer Perceptron)模型使用RandomSearchCV获取最优参数及可视化
  10. 阿里云 mysql主从_阿里云MySQL主从_Mater Slave_主备同步_MySQL主从_MySQL延迟-云栖社区-阿里云...