A detailed explanation of the double linked list structure in Redis _redis

Source: Internet
Author: User
Tags constant prev redis

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; 
  } 

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.