hlist (hash list)The corresponding hash algorithm can be used to quickly find the related linked list head and node.
In some scenarios, it is more appropriate than the list (a doubly linked list) provided by the Go standard library.
In accordance with the source code in List.h, I implemented a Go language version of the hlist example.
First of all, the composition of hlist:
in the hlist (hash list),
The head node is represented by struct Hlist_head, hlist_head only a first pointer.
Normal nodes are represented using struct Hlist_node.
There are several special places in the source code:
1. In struct Hlist_node There is a level two pointer in the **pprev,
Pprev points to the next address of the previous variable in the current Hlist_node variable,
If it is the first element, this value points to the address of
If it is the last node, it points to null.
2.container_of
There is a macro definition in the source code:
#define Hlist_entry (PTR, type, member) container_of (Ptr,type,member)
Using some techniques, you can get the first address of the structure by member (that is, the linked list node) inside the struct body.
So when called in a C + + application, it is commonly defined as follows:
struct MYST {
int data;
struct List_head head;
struct Hlist_node node;
} *myst;
In go, I changed it to:
Type hlelement struct {
Next *hlelement
Pprev **hlelement
Value interface{}
}
With the interface{} feature, you can set the custom struct to value. When used, through interface{}
Convert back to original object
3. Use List_poison in Hlist_del () instead of (= = NULL) Form
N->next = List_poison1;
N->pprev = List_poison2;
The reason might be to delete node through this tag, and if you use this node elsewhere,
can be used to distinguish whether or not a node that has been deleted has been referenced.
in my case, this is an optional feature, just take a look at the application.
So in the go version, I directly removed the List_poison, directly set it to nil.
4. When traversing a linked list, a safe version is provided to prevent interrupts caused by the deletion of the node
In the Go version I also provide the relevant implementation.
Specific implementation and test code:
Package main//hlist (imitation Linux kernel data structure hlist, can refer to kernel source list.h)//author:xiong Chuan liang//date:2015-2-12import ("FMT") func Main () {/////////////////////////////////////* hash bucket 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 usage Demo:") 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 traverse one of the head (Lst[1]) corresponds to the linked list:") F: = Func (e *hlelement) bool {FMT. Println ("Hlelement.value =", E.value) return True}for_each_safe (&lst[1], f) fmt. Println ("\ n////////////////////////////////////") fmt. Println ("Demo 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 Traverse list See effect:") For_each (Hhead, F) fmt. Println ("\ n////////////////////////////////////") fmt. Println ("\ n Test movelist:lst[1] = movelist (0->1)") movelist (&lst[0], &lst[1]) For_each_safe (&lst[1] , f) fmt. Println ("\ n////////////////////////////////////") fmt. Println ("Traversing the linked list from the specified element:") For_each_safe_from (elem2, F) fmt. Println ("\ n////////////////////////////////////") fmt. Println ("Put the custom struct into the list:") 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 corresponding linked list is blank!")} else {fmt. Println ("empty (hhead) = False:hhead corresponds to the linked list is not empty!")} Hheadempty: = &hlhead{}if Empty (hheadempty) {fmt. Println ("empty (hheadempty) = True:hheadempty corresponding linked list is blank!")} else {fmt. Println ("empty (hheadempty) = False:hheadempty corresponds to the linked list is not empty!")} If unhashed (elem1) {fmt. Println ("unhashed (elem1) = True:elem1 not in the list!")} else {fmt. Println ("unhashed (elem1) = False:elem1 in the list! ")}}//demo with Structtype demo struct {Data string}//demo with hash algorithm func Gethash (c int) int {return (c% 16)}////////////////////// Type hlhead struct {First *hlelement}type hlelement struct {Next * Hlelementpprev **hlelementvalue Interface{}}type elemfunc func (e *hlelement) boolfunc for_each (H *HLHead, F ElemFunc) {PO S: = h.firstfor pos! = nil {if!f (POS) {Break}pos= pos. Next}}func For_each_safe (H *hlhead, F Elemfunc) {pos: = h.firstfor pos! = Nil {n: = pos. Nextif!f (pos) {break}pos = N}}func for_each_safe_from (h *hlelement, F Elemfunc) {pos: = h.nextfor pos! = Nil {n: = pos. Nextif!f (pos) {Break}pos = n}}//inserts the normal node n into the first node of the hash bucket corresponding to the head node H func addhead (n *hlelement, H *hlhead) {primary: = H.FIRSTN.N ext = firstif First! = nil {first. Pprev = &n.next}h.first = nn. Pprev = &h.first}//n: New node, Next: List func insertbefore (n *hlelement, next *hlelement) {pprev: = next. Pprevn.pprev = pprevn. Next = Nextnext. Pprev = &n.nextif Pprev! = Nil {//will be the value of the previous node next, point to the new node N*pprev = n}}//n: List, Next: New node Func InsertAfter (n *hlelement, NE XT *hlelement) {next. Next = N.nextn.next = Nextnext. Pprev = &n.nextif Next. Next! = Nil {next. Next.pprev = &next. next}}//Mobile Listfunc movelist (old, new *hlhead) {new. First = old. Firstif New. First! = Nil {//linked list refers to a directional element that is not empty, changing its pprev point to Newnew.First.PPrev = &new. First}old. First = nil}//Determines whether the node is already in the linked list, as true, indicating that it is not in one of the Func unhashed (H*hlelement) bool {return (H.pprev = = nil)}//determine if the linked list is null func empty (h *hlhead) bool {return (H.first = nil)}//Delete node Func remove ( N *hlelement) {Next: = N.nextpprev: = n.pprevif Pprev! = Nil {*pprev = next}if next! = Nil {next. Pprev = Pprev}n.next = Niln. Pprev = nil}////////////////////////////////////////////////////////////////////*/////////////////////////////// Hlist Usage Demo: i:0 hash:0i:1 hash:1i:2 hash:2i:3 hash:3i:4 hash:4i:5 hash:5i:6 hash:6i:7 Hash:7i:8 hash:8i:9 hash:9i:10 hash:10i:11 hash:11i:12 hash:12i:13 hash:13i:14 hash:14i:15 Hash:15i:16 hash:0i:17 hash:1i:18 hash:2i:19 hash:3 traverses the linked list of one head (Lst[1]): Hlelement.value = 17HLEleme Nt. Value = 1////////////////////////////////////demo Insertafter/insertbefore: Traverse list See effect: Hlelement.value = 1HLElement.Value = 2hlelement.value = 400hlelement.value = 300////////////////////////////////////Test movelist:lst[1] = MoveList (0-& gt;1) Hlelement.value = 16HLElemeNt. Value = 0////////////////////////////////////from the specified element to traverse the linked list: Hlelement.value = 400hlelement.value = 300//////////// Put the custom structure into the list: struct = cstruct = Bstruct = aint = 1int = 2int = 400int = 300///////////////// Remove (ELEMB): struct = cstruct = aint = 1int = 2int = 400int = 300////////////////////////////// Empty ()/unhashed (): Empty (hhead) = False:hhead The corresponding list is not empty! Empty (Hheadempty) = True:hheadempty The corresponding list is blank! unhashed (ELEM1) = False:elem1 in the linked list!*/
The example basically realizes the commonly used thing, realizes when mainly must pay attention to the Golang characteristic and with C's some difference.
Some references:
A copy of the List.h source code:
Http://lxr.free-electrons.com/source/include/linux/list.h
A very fine description of the hlist:
Http://blog.chinaunix.net/uid-22566367-id-2192969.html
MAIL: [Email protected]
blog:http://blog.csdn.net/xcl168
Go language porting Linux kernel data structure hlist