Chinaunix首页 | 论坛 | 博客
  • 博客访问: 303591
  • 博文数量: 82
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 490
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-13 10:58
文章分类

全部博文(82)

文章存档

2018年(2)

2017年(9)

2016年(71)

我的朋友

分类: C/C++

2017-01-10 22:06:59

双向循环链表插入和删除都非常方便,c编码中常常使用,下边代码是一个双向循环链表的例子。分为3个文件,list.h,  list.c,  main.cmain.c中是测试代码,将三个文件一起编译得到测试结果。list.h中的list_node_t可以嵌入任何结构体,能很方便的生成链表。而list_for_each_entry_next(pos, head), list_for_each_entry_prev(pos, head)list_for_each_entry_safe(pos, n, head) 可以方便的实现链表的遍历。


  文件list.h
  1. #ifndef LIST_H
  2. #define LIST_H

  3. typedef struct list_node {
  4.     struct list_node * next, * prev;
  5. } list_node_t;

  6. /** 初始化list_node_t */
  7. #define INIT_LIST_NODE(node) {&(node), &(node)}

  8. /** 得到member成员的偏移量 */
  9. #define member_offset(type, member)    \
  10.     ((size_t)&(((type*)0)->member))
  11.     
  12. /** 从member_ptr指针计算出其所在type类型的首地址 */
  13. #define type_list_entry(member_ptr, type, member) \
  14.     (type*)((char*)member_ptr - member_offset(type, member))

  15. /** 循环遍历head->next */
  16. #define list_for_each_entry_next(pos, head) \
  17.     for (pos = type_list_entry((head)->next, typeof(*pos), list); \
  18.          pos && (&pos->list != (head)); \
  19.          pos = type_list_entry(pos->list.next, typeof(*pos), list))

  20. /** 循环遍历head->prev */
  21. #define list_for_each_entry_prev(pos, head) \
  22.     for (pos = type_list_entry((head)->prev, typeof(*pos), list); \
  23.          pos && (&pos->list != (head)); \
  24.          pos = type_list_entry(pos->list.prev, typeof(*pos), list))

  25. /** 循环遍历head->next, 删除节点时使用 */
  26. #define list_for_each_entry_safe(pos, n, head) \
  27.     for (pos = type_list_entry((head)->next, typeof(*pos), list), \
  28.          n = type_list_entry((pos->list).next, typeof(*pos), list); \
  29.          pos && (&pos->list != (head)); \
  30.          pos = n, n = type_list_entry(n->list.next, typeof(*pos), list))

  31. /** 初始化list_node_t */
  32. void init_list_node(list_node_t * list);
  33. /** 把new节点插入到prev和next之间 */
  34. void add_node_to_list(list_node_t * new, list_node_t * prev, list_node_t * next);
  35. /** 把new节点插入到链表的第一个 */
  36. void add_node_to_list_head(list_node_t * new, list_node_t * head);
  37. /** 把new节点插入到链表的追后一个 */
  38. void add_node_to_list_tail(list_node_t * new, list_node_t * head);
  39. /** 把node节点从链表中分离出来 */
  40. void detach_node_from_list(list_node_t * node);
  41. /** 判断节点是否为空 */
  42. int list_is_empty(list_node_t * head);

  43. #endif

 文件list.c
  1. #include "list.h"

  2. void init_list_node(list_node_t * list)
  3. {
  4.     list->next = list;
  5.     list->prev = list;
  6. }

  7. void add_node_to_list(list_node_t * new, list_node_t * prev, list_node_t * next)
  8. {
  9.     next->prev = new;
  10.     new->next = next;
  11.     new->prev = prev;
  12.     prev->next = new;
  13. }

  14. void add_node_to_list_head(list_node_t * new, list_node_t * head)
  15. {
  16.     add_node_to_list(new, head, head->next);
  17. }

  18. void add_node_to_list_tail(list_node_t * new, list_node_t * head)
  19. {
  20.     add_node_to_list(new, head->prev, head);
  21. }

  22. void detach_node_from_list(list_node_t * node)
  23. {
  24.     list_node_t * prev = node->prev;
  25.     list_node_t * next = node->next;    
  26.     next->prev = prev;
  27.     prev->next = next;
  28. }

  29. int list_is_empty(list_node_t * head)
  30. {
  31.     return head->next == head;
  32. }

  测试文件main.c
  1. #include "list.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>

  5. typedef struct test_info {
  6.     int count;
  7.     list_node_t list;
  8. } test_info_t;

  9. void test_node_list()
  10. {
  11.     /* 新建并初始化头结点 */
  12.     list_node_t list_node_head = INIT_LIST_NODE(list_node_head);

  13.     /* 新建由test_info_t节点构成的链表 */
  14.     int i = 0;
  15.     for(; i < 5; i++) {
  16.         test_info_t * new_node = (test_info_t * )malloc(sizeof(test_info_t));
  17.         memset(new_node, 0, sizeof(test_info_t));

  18.         new_node->count = i;
  19.         add_node_to_list_tail(&new_node->list, &list_node_head);
  20.     }

  21.     /* 从头到尾循环遍历 */
  22.     test_info_t * pos = NULL;
  23.     list_for_each_entry_next(pos, &list_node_head) {
  24.         printf("%d, ", pos->count);
  25.     }
  26.     printf("\n");

  27.     /* 从尾到头循环遍历 */
  28.     pos = NULL;
  29.     list_for_each_entry_prev(pos, &list_node_head) {
  30.         printf("%d, ", pos->count);
  31.     }
  32.     printf("\n");

  33.     /* 删除节点 */
  34.     test_info_t * n = NULL;
  35.     pos = NULL;
  36.     list_for_each_entry_safe(pos, n, &list_node_head) {
  37.         if (2 == pos->count) {
  38.             detach_node_from_list(&pos->list);
  39.             free(pos);
  40.         }
  41.     }
  42.     
  43.     pos = NULL;
  44.     list_for_each_entry_prev(pos, &list_node_head) {
  45.         printf("%d, ", pos->count);
  46.     }
  47.     printf("\n");
  48. }    

  49. int main()
  50. {
  51.     test_node_list();
  52.     return 0;
  53. }

  编译后执行结果:
  1. [root@192 demo]# ./main
  2. 0, 1, 2, 3, 4,
  3. 4, 3, 2, 1, 0,
  4. 4, 3, 1, 0,

阅读(1698) | 评论(0) | 转发(0) |
0

上一篇:cJSON使用简介

下一篇:收藏文集

给主人留下些什么吧!~~