Position of the double-ended linked list in Redis: as a general data structure, it is widely used in Redis. It is one of the underlying implementations of the Redis list structure and is also used by a large number of Redis modules to build other functions.
1. For the definition of the Redis double-ended list, see adlist. h and adlist. c. Consistent with the definition of a double-linked table, a linked list node is introduced, and a head and end node is added to build a double-ended linked list.
The linked list nodes are defined as follows:
/* Node, List, and Iterator are the only data structures used currently. * // ** linked list node */typedef struct listNode {// struct listNode * prev; // subsequent node struct listNode * next; // value void * value ;} listNode;
The linked list is defined as follows:
/** Linked list */typedef struct list {// header pointer listNode * head; // table tail pointer listNode * tail; // number of nodes unsigned long len; // copy function void * (* dup) (void * ptr); // release function void (* free) (void * ptr); // Compare function int (* match) (void * ptr, void * key);} list;
Shows the structure of the double-ended linked list:
The APIs of the double-ended linked list are as follows:
Function |
Function |
Algorithm complexity |
ListCreate |
Create a new linked list |
O (1) |
ListRelease |
Release the linked list and the nodes contained in the linked list |
O (N) |
ListDup |
Create a copy of a given linked list |
O (N) |
ListRotate |
Retrieve the End Node of the table in the linked list and insert it to the header. |
O (1) |
ListAddNodeHead |
Add the node containing the specified value to the table header of the linked list. |
O (1) |
ListAddNodeTail |
Add the node containing the specified value to the end of the linked table. |
O (1) |
ListInsertNode |
Add a node containing a specified value before or after a node |
O (1) |
ListDelNode |
Delete a given Node |
O (1) |
ListSearchKey |
Search for nodes that match the given key in the linked list |
O (N) |
ListIndex |
Returns the corresponding node in the list for the given index. |
O (N) |
ListLength |
Returns the number of nodes in a given linked list. |
O (1) |
ListFirst |
Returns the table header node of the linked list. |
O (1) |
ListLast |
Returns the End Node of the table in the linked list. |
O (1) |
ListPrevNode |
Returns the previous node of a given node. |
O (1) |
ListNextNode |
Returns the last node of a given node. |
O (1) |
ListNodeValue |
Returns the value of a given node. |
O (1) |
The structure of the dual-end list reduces the complexity of adding or deleting two common operations to O (1). This reduces the time overhead by implementing some internal commands such as LPUSH and RPOP.
2. The iterator Redis implements a double-ended linked list iterator to facilitate iteration of the double-ended linked list in two directions. The next pointer of the node iterates from the header to the end of the table along the node prev pointer. The iterator from the end of the table to the header is defined as follows:
/** Linked list iterator */typedef struct listIter {// next node listNode * next; // iteration direction int direction;} listIter;
The implementation of the get iterator is as follows:
/** Create an iterator for the list. The iteration direction is determined by the direction parameter. ** each time you call listNext () on the iterator (), the iterator returns the next node of the list ** this function does not handle the failure ** T = O (1) */listIter * listGetIterator (list * list, int direction) {listIter * iter; if (iter = zmalloc (sizeof (* iter) = NULL) return NULL; // depending on the direction of iteration, point the iterator pointer to the header or table end if (direction = AL_START_HEAD) iter-> next = list-> head; else iter-> next = list-> tail; // record direction iter-> direction = direction; return iter ;}
The iterator returns the next node each time based on the iteration direction.
The iterator API is as follows:
Function |
Function |
Algorithm complexity |
ListGetIterator |
Create a list iterator |
O (1) |
ListReleaseIterator |
Release iterator |
O (1) |
ListRewind |
Point the iterator pointer to the header |
O (1) |
ListRewindTail |
Point the iterator pointer to the end of the table |
O (1) |
ListNext |
Retrieves the node to which the iterator is currently directed. |
O (1) |
3. double-ended linked list purpose 3.1 When the Redis list type performs operations on the list type key, the underlying operation of the program may be the double-ended linked list. For example, run commands such as RPUSH, LPOP, and LLEN.
redis> RPUSH brands Apple Microsoft Google(integer) 3redis> LPOP brands"Apple"redis> LLEN brands(integer) 2redis> LRANGE brands 0 -11) "Microsoft"2) "Google"
The usage of RPUSH is as follows. For other commands, see
Command Manual.
RPUSH key value [value...] insert one or more values to the end of the table (rightmost) of the list key ). If there are multiple value values, each value is inserted from left to right to the end of the table. For example, run RPUSH mylist a B c on an empty list mylist, the result list is a B c, which is equivalent to Executing command RPUSH mylist a, RPUSH mylist B, and RPUSH mylist c.
If the key does not exist, an empty list is created and RPUSH is executed.
If the key exists but is not of the list type, an error is returned.
3.2apart from the list type, the double-ended linked list is also applied by many internal Redis modules:
The transaction module uses the double-ended linked list to save the input command in sequence. The server module uses the double-ended linked list to store multiple client subscription/sending modules. The double-ended linked list is used to store multiple client event modules in the subscription mode. to save the time event)