当前位置 博文首页 > 积水成渊:好用的链表操作库。

    积水成渊:好用的链表操作库。

    作者:[db:作者] 时间:2021-07-13 21:54

    1. linklist.c


    #include "linklist.h"
    
    /* Allocate new list. */
    struct list *
    list_new (void)
    {
    
      return (struct list *)calloc(1, sizeof(struct list));
    }
    
    /* Free list. */
    void
    list_free (struct list *l)
    {
      free(l);
    }
    
    /* Allocate new listnode.  Internal use only. */
    static struct listnode *
    listnode_new (void)
    {
      return (struct listnode *)calloc(1,sizeof (struct listnode));
    }
    
    /* Free listnode. */
    static void
    listnode_free (struct listnode *node)
    {
      free(node);
    }
    
    /* Add new data to the list. */
    void
    listnode_add (struct list *list, void *val)
    {
      struct listnode *node;
      
      assert (val != NULL);
      
      node = listnode_new ();
    
      node->prev = list->tail;
      node->data = val;
    
      if (list->head == NULL)
        list->head = node;
      else
        list->tail->next = node;
      list->tail = node;
    
      list->count++;
    }
    
    /*
     * Add a node to the list.  If the list was sorted according to the
     * cmp function, insert a new node with the given val such that the
     * list remains sorted.  The new node is always inserted; there is no
     * notion of omitting duplicates.
     */
    void
    listnode_add_sort (struct list *list, void *val)
    {
      struct listnode *n;
      struct listnode *new;
      
      assert (val != NULL);
      
      new = listnode_new ();
      new->data = val;
    
      if (list->cmp)
        {
          for (n = list->head; n; n = n->next)
    	{
    	  if ((*list->cmp) (val, n->data) < 0)
    	    {	    
    	      new->next = n;
    	      new->prev = n->prev;
    
    	      if (n->prev)
    		n->prev->next = new;
    	      else
    		list->head = new;
    	      n->prev = new;
    	      list->count++;
    	      return;
    	    }
    	}
        }
    
      new->prev = list->tail;
    
      if (list->tail)
        list->tail->next = new;
      else
        list->head = new;
    
      list->tail = new;
      list->count++;
    }
    
    void
    listnode_add_after (struct list *list, struct listnode *pp, void *val)
    {
      struct listnode *nn;
      
      assert (val != NULL);
      
      nn = listnode_new ();
      nn->data = val;
    
      if (pp == NULL)
        {
          if (list->head)
    	list->head->prev = nn;
          else
    	list->tail = nn;
    
          nn->next = list->head;
          nn->prev = pp;
    
          list->head = nn;
        }
      else
        {
          if (pp->next)
    	pp->next->prev = nn;
          else
    	list->tail = nn;
    
          nn->next = pp->next;
          nn->prev = pp;
    
          pp->next = nn;
        }
      list->count++;
    }
    
    
    /* Delete specific date pointer from the list. */
    void
    listnode_delete (struct list *list, void *val)
    {
      struct listnode *node;
    
      assert(list);
      for (node = list->head; node; node = node->next)
        {
          if (node->data == val)
    	{
    	  if (node->prev)
    	    node->prev->next = node->next;
    	  else
    	    list->head = node->next;
    
    	  if (node->next)
    	    node->next->prev = node->prev;
    	  else
    	    list->tail = node->prev;
    
    	  list->count--;
    	  listnode_free (node);
    	  return;
    	}
        }
    }
    
    /* Return first node's data if it is there.  */
    void *
    listnode_head (struct list *list)
    {
      struct listnode *node;
    
      assert(list);
      node = list->head;
    
      if (node)
        return node->data;
      return NULL;
    }
    
    /* Delete all listnode from the list. */
    void
    list_delete_all_node (struct list *list)
    {
      struct listnode *node;
      struct listnode *next;
    
      assert(list);
      for (node = list->head; node; node = next)
        {
          next = node->next;
          if (list->del)
    	(*list->del) (node->data);
          listnode_free (node);
        }
      list->head = list->tail = NULL;
      list->count = 0;
    }
    
    /* Delete all listnode then free list itself. */
    void
    list_delete (struct list *list)
    {
      assert(list);
      list_delete_all_node (list);
      list_free (list);
    }
    
    /* Lookup the node which has given data. */
    struct listnode *
    listnode_lookup (struct list *list, void *data)
    {
      struct listnode *node;
    
      assert(list);
      for (node = listhead(list); node; node = listnextnode (node))
        if (data == listgetdata (node))
          return node;
      return NULL;
    }
    
    /* Delete the node from list.. */
    void
    list_delete_node (struct list *list, struct listnode *node)
    {
      if (node->prev)
        node->prev->next = node->next;
      else
        list->head = node->next;
      if (node->next)
        node->next->prev = node->prev;
      else
        list->tail = node->prev;
      list->count--;
      listnode_free (node);
    }
    
    
    void
    list_add_node_prev (struct list *list, struct listnode *current, void *val)
    {
      struct listnode *node;
      
      assert (val != NULL);
      
      node = listnode_new ();
      node->next = current;
      node->data = val;
    
      if (current->prev == NULL)
        list->head = node;
      else
        current->prev->next = node;
    
      node->prev = current->prev;
      current->prev = node;
    
      list->count++;
    }
    
    void
    list_add_node_next (struct list *list, struct listnode *current, void *val)
    {
      struct listnode *node;
      
      assert (val != NULL);
      
      node = listnode_new ();
      node->prev = current;
      node->data = val;
    
      if (current->next == NULL)
        list->tail = node;
      else
        current->next->prev = node;
    
      node->next = current->next;
      current->next = node;
    
      list->count++;
    }
    
    void
    list_add_list (struct list *l, struct list *m)
    {
      struct listnode *n;
    
      for (n = listhead (m); n; n = listnextnode (n))
        listnode_add (l, n->data);
    }
    


    2. linklist.h


    #ifndef __LINKLIST_H
    #define __LINKLIST_H
    
    /* listnodes must always contain data to be valid. Adding an empty node
     * to a list is invalid
     */
    struct listnode 
    {
      struct listnode *next;
      struct listnode *prev;
      
      /* private member, use getdata() to retrieve, do not access directly */
      void *data;
    };
    
    struct list 
    {
      struct listnode *head;
      struct listnode *tail;
    
      /* invariant: count is the number of listnodes in the list */
      unsigned int count;
    
      /*
       * Returns -1 if val1 < val2, 0 if equal?, 1 if val1 > val2.
       * Used as definition of sorted for listnode_add_sort
       */
      int (*cmp) (void *val1, void *val2);
    
      /* callback to free user-owned data when listnode is deleted. supplying
       * this callback is very much encouraged!
       */
      void (*del) (void *val);
    };
    
    #define listnextnode(X) ((X) ? ((X)->next) : NULL)
    #define listhead(X) ((X) ? ((X)->head) : NULL)
    #define listtail(X) ((X) ? ((X)->tail) : NULL)
    #define listcount(X) ((X)->count)
    #define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL)
    #define listgetdata(X) (assert((X)->data != NULL), (X)->data)
    
    /* Prototypes. */
    extern struct list *list_new(void); /* encouraged: set list.del callback on new lists */
    extern void list_free (struct list *);
    
    extern void listnode_add (struct list *, void *);
    extern void listnode_add_sort (struct list *, void *);
    extern void listnode_add_after (struct list *, struct listnode *, void *);
    extern void listnode_delete (struct list *, void *);
    extern struct listnode *listnode_lookup (struct list *, void *);
    extern void *listnode_head (struct list *);
    
    extern void list_delete (struct list *);
    extern void list_delete_all_node (struct list *);
    
    extern void list_delete_node (struct list *, struct listnode *);
    extern void list_add_node_prev (struct list *, struct listnode *, void *);
    extern void list_add_node_next (struct list *, struct listnode *, void *);
    extern void list_add_list (struct list *, struct list *);
    
    /* List iteration macro. 
     * Usage: for (ALL_LIST_ELEMENTS (...) { ... }
     * It is safe to delete the listnode using this macro.
     */
    #define ALL_LIST_ELEMENTS(list,node,nextnode,data) \
      (node) = listhead(list), ((data) = NULL); \
      (node) != NULL && \
        ((data) = listgetdata(node),(nextnode) = node->next, 1); \
      (node) = (nextnode), ((data) = NULL)
    
    /* read-only list iteration macro.
     * Usage: as per ALL_LIST_ELEMENTS, but not safe to delete the listnode Only
     * use this macro when it is *immediately obvious* the listnode is not
     * deleted in the body of the loop. Does not have forward-reference overhead
     * of previous macro.
     */
    #define ALL_LIST_ELEMENTS_RO(list,node,data) \
      (node) = listhead(list), ((data) = NULL);\
      (node) != NULL && ((data) = listgetdata(node), 1); \
      (node) = listnextnode(node), ((data) = NULL)
    
    /* these *do not* cleanup list nodes and referenced data, as the functions
     * do - these macros simply {de,at}tach a listnode from/to a list.
     */
     
    /* List node attach macro.  */
    #define LISTNODE_ATTACH(L,N) \
      do { \
        (N)->prev = (L)->tail; \
        if ((L)->head == NULL) \
          (L)->head = (N); \
        else \
          (L)->tail->next = (N); \
        (L)->tail = (N); \
        (L)->count++; \
      } while (0)
    
    /* List node detach macro.  */
    #define LISTNODE_DETACH(L,N) \
      do { \
        if ((N)->prev) \
          (N)->prev->next = (N)->next; \
        else \
          (L)->head = (N)->next; \
        if ((N)->next) \
          (N)->next->prev = (N)->prev; \
        else \
          (L)->tail = (N)->prev; \
        (L)->count--; \
      } while (0)
    
    
    #endif /* __LINKLIST_H */
    


    cs