The basic structure of double linked list in Redis:
1. Node structure
typedef struct LISTNODE {
struct listnode *prev;//forward nodes struct ListNode *next;
//Back to node
void *value; The value of the node
} listnode;
2. Two-way linked list structure
typedef struct LIST {
listnode *head; Head node
listnode *tail; Tail node
void * (*dup) (void *ptr);//copy function
Void (*free) (void *ptr) ; free function
int (*match) (void *ptr, void *key);//matching function, lookup node using
unsigned long len; The length of the two-way linked list is the number of nodes
} list;
3. Two-way linked list traversal device
typedef struct LISTITER {
listnode *next; Next node
int direction;
} Listiter;
Direction definition
#define AL_START_HEAD 0//forward lookup
#define AL_START_TAIL 1 //Backward Lookup
4. Macro definition function
#define LISTLENGTH (L) ((l)->len)
#define LISTFIRST (L) ((l)->head)
#define LISTLAST (L) ((l)->tail)
#define LISTPREVNODE (n) ((n)->prev)
#define LISTNEXTNODE (n) ((n)->next)
#define LISTNODEVALUE (N) ((n)->value)
#define LISTSETDUPMETHOD (L,m) ((l)->dup = (m))
#define Listsetfreemethod (L,m) ((l)->free = (m))
#define Listsetmatchmethod (L,m) ((l)->match = (m))
#define LISTGETDUPMETHOD (L) ((l)->dup)
#define Listgetfree (l) ((l)->free)
#define LISTGETMATCHMETHOD (L) ((l)->match)
5. Defining functions
List *listcreate (void); Create a new linked list.
The linked list can be released using the Alfree () method.
However, before using the Alfree () method, you need to release the value of the user freeing the private node.
Returns NULL if no success was created, and returns a pointer to the new linked list if the creation succeeds. void Listrelease (list *list); Releases the entire list, the function does not fail to execute.
Call the Zfree (list *list) method, defined in ZMALLOC.C. List *listaddnodehead (list *list, void *value); Adds a node list *listaddnodetail (list *list, void *value) to the header of the list; Add a node to the tail of the list *listinsertnode (list *list, ListNode *old_node, void *value, int after);//Insert node to a node after in direction void
Listdelnode (list *list, ListNode *node);//delete a specific node from the linked list, and the caller frees the value of a particular private node.
The function does not perform a failure listiter *listgetiterator (list *list, int direction);//Returns an iterator for a list. The Listnext () method of the iterator returns the next node of the list.
Direction is the direction//The function will not fail to execute.
ListNode *listnext (Listiter *iter); void Listreleaseiterator (Listiter *iter);
Frees the memory of the iterator. List *listdup (list *orig); Copy the entire linked list.
Returns NULL when memory overflows and returns a backup of the original list when successful The original list does not change, regardless of whether the method was executed successfully. ListNode *listsearchkey (list *list, void *key); Find key from a specific list of linked lists.
Success returns a pointer to the first matching node//or NULL if there is no match. ListNode *listindex (list *list, long index); The ordinal number starts at 0, and the index of the header of the list is 0.1 as the next node of the head node.
One analogy. Negative integers are used to indicate counting from the tail. -1 for the last node,-2 penultimate node//if the index of the linked list is exceeded, return null void Listrewind (list *list, Listiter *li) {li-
>next = list->head;
Li->direction = Al_start_head;
} void Listrewindtail (list *list, Listiter *li) {li->next = list->tail;
Li->direction = Al_start_tail; } void Listrotate (list *list);
Rotate the linked list, remove the tail node, and insert the head.
The list structure and the API for the LISTNODE structure
list and ListNode have their own family of APIs, here posted to learn the source of Redis (PS: The following code is I imitate the Redis rewrite can directly compile the code to run)
List *listcreate (void)
/**
* Create a new list
* *
T = O (1) */
list *listcreate (void)
{
struct list *list;
Allocates the memory list
= (struct list *) malloc (sizeof (struct list)) to the listing structure;
if (list = = null) return
null;
Initialize attribute
list->head = List->tail = NULL;
List->len = 0;
List->dup = NULL;
List->free = NULL;
List->match = NULL;
return list;
}
void Listrelease (list *list)
/**
* Free entire list
*
* T = O (n), n for list length
/void Listrelease (list *list)
{
unsigned long len;
ListNode *current, *next;
Current = list->head;
Len = list->len;
while (Len-) {
next = current->next;
If the list has its own free method, it first calls the node value if
(list->free) list->free (current->value);
Release node free
(current);
current = next;
Free (list);
List *listaddnodehead (list *list, void *value)
/**
* Creates a new node that contains the given value and adds it to the table header
*
* T = O (1)/
list
*listaddnodehead (list *list, void *value) c6/>{
ListNode *node;
node = (ListNode *) malloc (sizeof (ListNode));
if (node = null) return
null;
Node->value = value;
if (List->len = = 0) {
//First node
list->head = list->tail = node;
Node->prev = Node->next = NULL;
} else {
//not the first node
node->prev = NULL;
Node->next = list->head;
List->head->prev = node;
list->head = node;
}
List->len + +;
return list;
}
list *listaddnodetail (list *list, void *value)
/**
* Creates a new node that contains the given value and adds it to the footer of the list
*
* T = O (1)/
list *listaddnodetail (list *list, void *value) c6/>{
ListNode *node;
node = (ListNode *) malloc (sizeof (ListNode));
if (node = null) return
null;
if (List->len = = 0) {
//First node
list->head = list->tail = node;
Node->prev = Node->next = NULL;
} else {
//not the first node
Node->prev = list->tail;
Node->next = NULL;
list->tail->next = node;
list->tail = node;
}
List->len + +;
return list;
}
List *listinsertnode (list *list, ListNode *old_node, void *value, int after)
/** * Creates a node that contains a value of * and inserts the new node before or after the Old_node, based on the instructions of the after parameter * * T = O (1)/list *listinsertnod
E (list *list, ListNode *old_node, void *value, int after) {ListNode *node;
node = (ListNode *) malloc (sizeof (ListNode));
if (node = null) return null;
if (after) {//insert after old_node Node->prev = Old_node;
Node->next = old_node->next;
Processing the footer node if (list->tail = = Old_node) {list->tail = node;
} else {//insert before old_node node->next = Old_node;
Node->prev = old_node->prev;
Processing the header node if (list->head = = Old_node) {list->head = node;
}//Update pointers to predecessor and successor nodes (this place is classic, save code) if (Node->prev!= NULL) {node->prev->next = node;
} if (Node->next!= NULL) {node->next->prev = node;
}//Update list node List->len + +; return list;
}
void Listdelnode (list *list, ListNode *node)
/**
* Release the given node in the list
*
* T = O (1)/
void Listdelnode (list *list, ListNode *node)
{
//Process precursor node pointer
if (node->prev) {
node->prev->next = node->next;
} else {
list->head = node-> Next;
}
Process the successor Node
if (node->next) {
Node->next->prev = node->prev;
} else {
List->tail = node->prev;
}
Release node value
if (list->free) List->free (node->value);
Release node free
(nodes);
Update list node number
List->len-;
}
iterators
in fact, I am very unfamiliar with the concept of iterators, because I am a pure C programmer, will not C + +, here directly with the study!
Redis implements an iterator for the list structure to traverse the linked list
The structure of the iterator is defined as follows:
/**
* List iterator *
/typedef struct LISTITER {
//Next node
listnode *next;
Iterative direction
int direction;
} Listiter;
Direction determines whether the iterator is to iterate backwards along the next pointer or to iterate forward along the Prev pointer, which can be a Al_start_head constant or a Al_start_tail constant in adlist.h:
#define AL_START_HEAD 0
#define AL_START_TAIL 1
Learn about the API implementations of iterators:
Listiter *listgetiterator (list *list, int direction)
/**
* Create an iterator for list lists, the iteration direction is determined by the parameter direction
*
* Each time the iterator Listnext (), the iterator returns the next node of the list
*
* T = O (1)
* * *
listiter *listgetiterator (list *list, int direction)
{
listiter *iter;
ITER = (Listiter *) malloc (sizeof (Listiter));
if (iter = null) return
null;
Depending on the direction of the iterator, the pointer to the iterator is pointed to the table header or footer
if (direction = al_start_head) {
iter->next = list->head;
} else { C17/>iter->next = list->tail;
}
Record direction
iter->direction = direction;
return iter;
}
void Listrewind (list *list, Listiter *li)
/** * Returns the iterator
's iteration pointer back to the list header
*
* T = O (1)/
void Listrewind (list *list, Listiter *li)
{
Li->next = list->head;
Li->direction = Al_start_head;
}
void Listrewindtail (list *list, Listiter *li)
/**
* Rewind The iterator's iteration pointer back to the list's footer
*
T = O (1)/
void Listrewindtail (list *list, Listiter *li)
{
Li->next = list->tail;
Li->direction = Al_start_tail;
}
ListNode *listnext (Listiter *iter)
The/**
* function either returns the current node or returns NULL, so the common usage is:
* iter = listgetiterator (list, <direction>);
* WHILE (node = Listnext (iter))!= NULL) {
* dosomethingwith (Listnodevalue (node));
*}
* *
T = O (1)
/
listnode *listnext (listiter *iter)
{
ListNode *current = iter->next;< C13/>if (current!= NULL) {
//depending on the iteration direction, select Node
if (iter->direction = = al_start_head)
Iter->next = current->next;
else
Iter->next = current->prev;
}
return current;
}