adlist
Adlist is one of the basic data structures of Redis. It is a two-way linked list and records the length of the linked list. The iterator of adlist records the iteration node and direction. I think the implementation of list is better than STL
Several important structures
The implementation of adlist is relatively simple. Basically, you can write all the implementation functions quickly after writing the code related to the linked list
/*
* Double end linked list node
*/
typedef struct listNode {
// Front node
struct listNode *prev;
// Post node
struct listNode *next;
// Node value
void *value;
} listNode;
/*
* Double ended list iterator
*/
typedef struct listIter {
// Current iterated node
listNode *next;
// Direction of iteration
int direction;
} listIter;
// Iteration from header to tail
#define AL_START_HEAD 0
// Iterating from tail to header
#define AL_START_TAIL 1
/*
* Double ended list structure
*/
typedef struct list {
// header node
listNode *head;
// Tail node
listNode *tail;
// Node value copy function
void *(*dup)(void *ptr);
// Node value release function
void (*free)(void *ptr);
// Node value comparison function
int (*match)(void *ptr, void *key);
// Number of nodes in the list
unsigned long len;
} list;
Overview of basic functions
function | function | Complexity |
---|---|---|
listCreate | Create linked list | O(1) |
listRelease | Free, reclaim space | O(N) |
listInsertNode | Insertion node | O(1) |
listDelNode | Delete node | O(1) |
listSearchKey | Search node | O(N) |
listGetIterator | Get iterator | O(1) |
... | ... | ... |
Other macro / function implementations are simple. No introduction
listCreate
// Create an empty list without nodes
list *listCreate(void) {
struct list *list;
// Allocated memory
if ((list = zmalloc(sizeof(*list))) == NULL)
return NULL;
// Initialize properties
list->head = list->tail = NULL;
list->len = 0;
list->dup = NULL;
list->free = NULL;
list->match = NULL;
return list;
}
listRelease
// Release all nodes and then release List
void listRelease(list *list) {
unsigned long len;
listNode *current, *next;
// Pointer to head
current = list->head;
// Traverse the entire list
len = list->len;
while(len--) {
next = current->next;
// If there is a set value release function, call it
if (list->free) list->free(current->value);
// Release node structure
zfree(current);
current = next;
}
// Release list structure
zfree(list);
}
listInsertNode
// Insert a new node before / after the given node
list *listInsertNode(list *list, listNode *old_node, void *value, int after) {
listNode *node;
// Create a new node
if ((node = zmalloc(sizeof(*node))) == NULL)
return NULL;
// Saved value
node->value = value;
// After adding a new node to the given node
if (after) {
node->prev = old_node;
node->next = old_node->next;
// Given node is the original table tail node
if (list->tail == old_node) {
list->tail = node;
}
// Before adding a new node to a given node
} else {
node->next = old_node;
node->prev = old_node->prev;
// Given node is the original header node
if (list->head == old_node) {
list->head = node;
}
}
// Update new node's leading pointer
if (node->prev != NULL) {
node->prev->next = node;
}
// Update post pointer for new node
if (node->next != NULL) {
node->next->prev = node;
}
// Update the number of linked list nodes
list->len++;
return list;
}
listDelNode
// Delete node
void listDelNode(list *list, listNode *node) {
// Adjust the pointer of the front node
if (node->prev)
node->prev->next = node->next;
else
list->head = node->next;
// Adjust the pointer of the post node
if (node->next)
node->next->prev = node->prev;
else
list->tail = node->prev;
// Release value
if (list->free) list->free(node->value);
// Release node
zfree(node);
// Number of linked lists minus one
list->len--;
}
listSearchKey
// Find the node according to the given Key value, and return the first
listNode *listSearchKey(list *list, void *key) {
listIter *iter;
listNode *node;
// Iterate the entire list
iter = listGetIterator(list, AL_START_HEAD);
while((node = listNext(iter)) != NULL) {
// Contrast
if (list->match) {
if (list->match(node->value, key)) {
listReleaseIterator(iter);
// find
return node;
}
} else {
if (key == node->value) {
listReleaseIterator(iter);
// find
return node;
}
}
}
listReleaseIterator(iter);
// not found
return NULL;
}
listGetIterator
// Get iterator by direction
listIter *listGetIterator(list *list, int direction) {
// Allocate memory for iterators
listIter *iter;
if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL;
// Set the starting node of the iterator according to the iteration direction
if (direction == AL_START_HEAD)
iter->next = list->head;
else
iter->next = list->tail;
// Record iteration direction
iter->direction = direction;
return iter;
}
Summary
The implementation of adlist is relatively simple. Compared with STL's list, the complexity is much smaller, but the basic functions are all available. STL provides functions such as merging and sorting. Adlist records the length of the linked list, which can be O(1) to get the length