Redis research-linked list of 3.1 data structures

Source: Internet
Author: User



We know that in the data structure, the biggest advantage of the list is the efficient implementation of dynamic increase, delete, change, the disadvantage is that the traversal is slow, so in Redis, a lot of the underlying implementation of functionality is based on the list, because Redis is based on the C language to write, so you can only implement their own linked list structure. For a regular doubly linked list node, we usually define it in the following way:


typedef struct Node{
   void *value;
   struct Node *prev;
   struct Node *next;
}Node; 




Redis, which is also defined in Adlist.h


Typedef struct listNode {

     // Front node
     Struct listNode *prev;

     // post node
     Struct listNode *next;

     // the value of the node
     Void *value;

} listNode;



The node definition above is the list of each element. In Redis, a doubly linked list is defined, and three operation functions (methods) are defined for the list:


Typedef struct list {

     // header node
     listNode *head;

     // footer 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);

     // The number of nodes included in the linked list
     Unsigned long len;

} list;


Also, an iterator that defines a doubly linked list


Typedef struct listIter {

     // the node to which the current iteration is
     listNode *next;

     // The direction of the iteration, from start to finish, from tail to head
     Int direction;

} listIter;











Seeing the two-way node above, we might ask in Redis whether he uses a linked list with a ring or a chain-free list? Our later function, because to implement a linked list of rings only need to use the list of the head of the prev is not NULL, tail next is not NULL to implement.



In Adlist.h, a bunch of macros are defined to implement simple function functions.


// returns the number of nodes contained in the given list
#define listLength(l) ((l)->len)
/ / Returns the header node of the given list
#define listFirst(l) ((l)->head)
// returns the footer node of the given list
#define listLast(l) ((l)->tail)
// return the predecessor of the given node
#define listPrevNode(n) ((n)->prev)
// return the back node of the given node
#define listNextNode(n) ((n)->next)
// return the value of the given node
#define listNodeValue(n) ((n)->value)

// Set the value copy function of the linked list l to m
#define listSetDupMethod(l,m) ((l)->dup = (m))
/ / Set the value release function of the linked list l to m
#define listSetFreeMethod(l,m) ((l)->free = (m))
// Set the comparison function of the linked list to m
#define listSetMatchMethod(l,m) ((l)->match = (m))

// returns the value copy function for the given list
#define listGetDupMethod(l) ((l)->dup)
// returns the value release function for the given list
#define listGetFree(l) ((l)->free)
/ / Returns the value comparison function of the given list
#define listGetMatchMethod(l) ((l)->match)





The above defines a basic function (macro) that gets the general properties of a linked list, based on how we typically manipulate a data structure, which should be a method (function) for defining creation, initialization, addition, deletion, and so on.




/ / Create a new list
List *listCreate(void)
{
    Struct list *list;

    // Allocate memory
    If ((list = zmalloc(sizeof(*list))) == NULL)
        Return NULL;

    // Initialize the property
    List->head = list->tail = NULL;
    List->len = 0;
    List->dup = NULL;
    List->free = NULL;
    List->match = NULL;

    Return list;
}
/ / Release the entire linked list and the nodes in the linked list
Void listRelease(list *list)
{
    Unsigned long len;
    listNode *current, *next;

    // Point to the head pointer. I always feel that there is a problem with the writing here. Add list==NULL?
    Current = list->head;
    // traverse the entire list
    Len = list->len;
    While(len--) {
        Next = current->next;

        // call it if there is a set value release function
        If (list->free) list->free(current->value);

        / / Release the node structure
        Zfree(current);

        Current = next;
    }

    / / Release the linked list structure
    Zfree(list);
}











/ / Create a node with a specified value to join the head of the list
List *listAddNodeHead(list *list, void *value)
{
    listNode *node;

    // allocate memory for the node
    If ((node = zmalloc(sizeof(*node))) == NULL)
        Return NULL;

    // save the value pointer
    Node->value = value;

    // Add node to empty list
    If (list->len == 0) {
        List->head = list->tail = node;
        Node->prev = node->next = NULL;
    // Add a node to a non-empty list
    } else {
        Node->prev = NULL;
        Node->next = list->head;
        List->head->prev = node;
        List->head = node;
    }

    / / Update the number of linked list nodes
    List->len++;

    Return list;
}











/ / Create a node with a specified value, and add to the end of the list
List *listAddNodeTail(list *list, void *value)
{
    listNode *node;

    // allocate memory for the new node
    If ((node = zmalloc(sizeof(*node))) == NULL)
        Return NULL;

    // save the value pointer
    Node->value = value;

    // The target list is empty
    If (list->len == 0) {
        List->head = list->tail = node;
        Node->prev = node->next = NULL;
    // The target list is not empty
    } else {
        Node->prev = list->tail;
        Node->next = NULL;
        List->tail->next = node;
        List->tail = node;
    }

    / / Update the number of linked list nodes
    List->len++;

    Return list;
}











 





 





/ / Create a node with the specified value, and according to the passed after parameter to determine whether to add to the specified node before or after
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;

    // save the value
    Node->value = value;

    // Add a new node to the given node
    If (after) {
        Node->prev = old_node;
        Node->next = old_node->next;
        // The given node is the original footer node
        If (list->tail == old_node) {
            List->tail = node;
        }
    // Add a new node before the given node
    } else {
        Node->next = old_node;
        Node->prev = old_node->prev;
        // The given node is the original header node
        If (list->head == old_node) {
            List->head = node;
        }
    }

    // Update the front pointer of the new node
    If (node->prev != NULL) {
        Node->prev->next = node;
    }
    // Update the post pointer of the new node
    If (node->next != NULL) {
        Node->next->prev = node;
    }

    / / Update the number of linked list nodes
    List->len++;

    Return list;
}



/ / Remove the specified node from the list
Void listDelNode(list *list, listNode *node)
{
    / / Adjust the pointer of the front node, I am particularly afraid of this writing when writing programs with java, because when you encounter a null pointer, here will be an error, so the following node should first determine whether it is air
    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 the node
    Zfree(node);

    // Reduce the number of linked lists by one
    List->len--;
}















/ / Create an iterator for a specific list
listIter *listGetIterator(list *list, int direction)
{
    // allocate memory for the iterator
    listIter *iter;
    If ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL;

    / / Set the start node of the iterator according to the iteration direction
    If (direction == AL_START_HEAD) / / here AL_START_HEAD==0
        Iter->next = list->head;
    Else
        Iter->next = list->tail;

    / / Record the iteration direction
    Iter->direction = direction;

    Return iter;
}








/ / Get the current node of the iterator, because the returned are pointers, so it can be changed
listNode *listNext(listIter *iter)
{
    listNode *current = iter->next;

    If (current != NULL) {
        / / Select the next node according to the direction
        If (iter->direction == AL_START_HEAD)
            // Save the next node to prevent the current node from being deleted and causing the pointer to be lost
            Iter->next = current->next;
        Else
            // Save the next node to prevent the current node from being deleted and causing the pointer to be lost
            Iter->next = current->prev;
    }

    Return current;
}



/ / Release the iterator
Void listReleaseIterator(listIter *iter) {
    Zfree(iter);
}





















/ / Copy the entire list, it should be noted that if the dup attribute of the original list is empty, then the two lists will share the pointer of the node, so be careful
List *listDup(list *orig)
{
    List *copy;
    listIter *iter;
    listNode *node;

    // Create a new linked list
    If ((copy = listCreate()) == NULL)
        Return NULL;

    / / Set the node value handler
    Copy->dup = orig->dup;
    Copy->free = orig->free;
    Copy->match = orig->match;

    / / Iterate the entire input list
    Iter = listGetIterator(orig, AL_START_HEAD);
    While((node = listNext(iter)) != NULL) {
        Void *value;

        / / Copy the node value to the new node
        If (copy->dup) {
            Value = copy->dup(node->value);
            If (value == NULL) {
                listRelease(copy);
                listReleaseIterator(iter);
                Return NULL;
            }
        } else
            Value = node->value;

        // will Node added to the linked list
        If (listAddNodeTail(copy, value) == NULL) {
            listRelease(copy);
            listReleaseIterator(iter);
            Return NULL;
        }
    }

    // release the iterator
    listReleaseIterator(iter);

    // return a copy
    Return copy;
}


















/ / Look for the first occurrence of the specified key node in the list, it should be noted that if the match function of the node in the list is empty, then directly compare the value of the pointer, find the first one to return, find no Return to NULL
listNode *listSearchKey(list *list, void *key)
{
    listIter *iter;
    listNode *node;

    / / Iterate the entire linked list
    Iter = listGetIterator(list, AL_START_HEAD);
    While((node = listNext(iter)) != NULL) {
        
        // Compared
        If (list->match) {
            If (list->match(node->value, key)) {
                listReleaseIterator(iter);
                // turn up
                Return node;
            }
        } else {
            If (key == node->value) {
                listReleaseIterator(iter);
                // turn up
                Return node;
            }
        }
    }
    
    listReleaseIterator(iter);

    // Not found
    Return NULL;
}

/ / Find the node of the specified index in the list, the node can be a positive number, or a negative number, when it is a negative number, -1 stands for the tail of the list, and so on, if not negative, then the index starts from 0
listNode *listIndex(list *list, long index) {
    listNode *n;

    // If the index is negative, look up from the end of the table
    If (index < 0) {
        Index = (-index)-1;
        n = list->tail;
        While(index-- && n) n = n->prev;
    // If the index is positive, look up from the header
    } else {
        n = list->head;
        While(index-- && n) n = n->next;
    }

    Return n;
}






 



 


The next two functions, according to the name, can be seen, back, what do you mean? Is the iterator of list
/ / Set to head->tail
Void listRewind(list *list, listIter *li) {
    Li->next = list->head;
    Li->direction = AL_START_HEAD;
}
/ / Set to tail->head
Void listRewindTail(list *list, listIter *li) {
    Li->next = list->tail;
    Li->direction = AL_START_TAIL;
}












The next function, which always finds that the name does not match the content of his implementation, is to make the tail of the linked list into the head of the list.





Void listRotate(list *list) {
     listNode *tail = list->tail;

     If (listLength(list) <= 1) return;

     /* Detach current tail */
     / / Remove the tail node
     List->tail = tail->prev;
     List->tail->next = NULL;

     /* Move it as head */
     // insert into the header
     List->head->prev = tail;
     Tail->prev = NULL;
     Tail->next = list->head;
     List->head = tail;
} 







Okay, so the Redis list is basically like this.








Redis Research-linked list of 3.1 data structures


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.