C语言面向对象编程(五):单链表实现

前面我们介绍了如何在 C 语言中引入面向对象语言的一些特性来进行面向对象编程,从本篇开始,我们使用前面提到的技巧,陆续实现几个例子,最后呢,会提供一个基本的 http server 实现(使用 libevent )。在这篇文章里,我们实现一个通用的数据结构:单链表。

    这里实现的单链表,可以存储任意数据类型,支持增、删、改、查找、插入等基本操作。(本文提供的是完整代码,可能有些长。)

    下面是头文件:

 
  1. #ifndef SLIST_H

  2. #define SLIST_H

  3.  
  4. #ifdef __cplusplus

  5. extern "C" {

  6. #endif

  7.  
  8. #define NODE_T(ptr, type) ((type*)ptr)

  9.  
  10. struct slist_node {

  11. struct slist_node * next;

  12. };

  13.  
  14. typedef void (*list_op_free_node)(struct slist_node *node);

  15. /*

  16. * return 0 on hit key, else return none zero

  17. */

  18. typedef int (*list_op_key_hit_test)(struct slist_node *node, void *key);

  19.  
  20. struct single_list {

  21. /* all the members must not be changed manually by callee */

  22. struct slist_node * head;

  23. struct slist_node * tail;

  24. int size; /* length of the list, do not change it manually*/

  25.  
  26. /* free method to delete the node

  27. */

  28. void (*free_node)(struct slist_node *node);

  29. /*

  30. * should be set by callee, used to locate node by key(*_by_key() method)

  31. * return 0 on hit key, else return none zero

  32. */

  33. int (*key_hit_test)(struct slist_node *node, void *key);

  34.  
  35. struct single_list *(*add)(struct single_list * list, struct slist_node * node);

  36. struct single_list *(*insert)(struct single_list * list, int pos, struct slist_node *node);

  37. /* NOTE: the original node at the pos will be freed by free_node */

  38. struct single_list *(*replace)(struct single_list *list, int pos, struct slist_node *node);

  39. struct slist_node *(*find_by_key)(struct single_list *, void * key);

  40. struct slist_node *(*first)(struct single_list* list);

  41. struct slist_node *(*last)(struct single_list* list);

  42. struct slist_node *(*at)(struct single_list * list, int pos);

  43. struct slist_node *(*take_at)(struct single_list * list, int pos);

  44. struct slist_node *(*take_by_key)(struct single_list * list, void *key);

  45. struct single_list *(*remove)(struct single_list * list, struct slist_node * node);

  46. struct single_list *(*remove_at)(struct single_list *list, int pos);

  47. struct single_list *(*remove_by_key)(struct single_list *list, void *key);

  48. int (*length)(struct single_list * list);

  49. void (*clear)(struct single_list * list);

  50. void (*deletor)(struct single_list *list);

  51. };

  52.  
  53. struct single_list * new_single_list(list_op_free_node op_free, list_op_key_hit_test op_cmp);

  54.  
  55. #ifdef __cplusplus

  56. }

  57. #endif

  58.  
  59. #endif // SLIST_H


    struct single_list 这个类,遵循我们前面介绍的基本原则,不再一一细说。有几点需要提一下:

  • 我们定义了 slist_node 作为链表节点的基类,用户自定义的节点,都必须从 slist_node 继承
  • 为了支持节点( node )的释放,我们引入一个回调函数 list_op_free_node ,这个回调需要在创建链表时传入
  • 为了支持查找,引入另外一个回调函数 list_op_key_hit_test 

    好了,下面看实现文件:

 
  1. #include "slist.h"

  2. #include <malloc.h>

  3.  
  4. static struct single_list * _add_node(struct single_list *list, struct slist_node *node)

  5. {

  6.  
  7. if(list->tail)

  8. {

  9. list->tail->next = node;

  10. node->next = 0;

  11. list->tail = node;

  12. list->size++;

  13. }

  14. else

  15. {

  16. list->head = node;

  17. list->tail = node;

  18. node->next = 0;

  19. list->size = 1;

  20. }

  21.  
  22. return list;

  23. }

  24.  
  25. static struct single_list * _insert_node(struct single_list * list, int pos, struct slist_node *node)

  26. {

  27. if(pos < list->size)

  28. {

  29. int i = 0;

  30. struct slist_node * p = list->head;

  31. struct slist_node * prev = list->head;

  32. for(; i < pos; i++)

  33. {

  34. prev = p;

  35. p = p->next;

  36. }

  37. if(p == list->head)

  38. {

  39. /* insert at head */

  40. node->next = list->head;

  41. list->head = node;

  42. }

  43. else

  44. {

  45. prev->next = node;

  46. node->next = p;

  47. }

  48.  
  49. if(node->next == 0) list->tail = node;

  50. list->size++;

  51. }

  52. else

  53. {

  54. list->add(list, node);

  55. }

  56.  
  57. return list;

  58. }

  59.  
  60. static struct single_list * _replace(struct single_list * list, int pos, struct slist_node *node)

  61. {

  62. if(pos < list->size)

  63. {

  64. int i = 0;

  65. struct slist_node * p = list->head;

  66. struct slist_node * prev = list->head;

  67. for(; i < pos; i++)

  68. {

  69. prev = p;

  70. p = p->next;

  71. }

  72. if(p == list->head)

  73. {

  74. /* replace at head */

  75. node->next = list->head->next;

  76. list->head = node;

  77. }

  78. else

  79. {

  80. prev->next = node;

  81. node->next = p->next;

  82. }

  83.  
  84. if(node->next == 0) list->tail = node;

  85.  
  86. if(list->free_node) list->free_node(p);

  87. else free(p);

  88. }

  89.  
  90. return list;

  91. }

  92.  
  93. static struct slist_node * _find_by_key(struct single_list *list, void * key)

  94. {

  95. if(list->key_hit_test)

  96. {

  97. struct slist_node * p = list->head;

  98. while(p)

  99. {

  100. if(list->key_hit_test(p, key) == 0) return p;

  101. p = p->next;

  102. }

  103. }

  104. return 0;

  105. }

  106.  
  107. static struct slist_node *_first_of(struct single_list* list)

  108. {

  109. return list->head;

  110. }

  111.  
  112. static struct slist_node *_last_of(struct single_list* list)

  113. {

  114. return list->tail;

  115. }

  116.  
  117. static struct slist_node *_node_at(struct single_list * list, int pos)

  118. {

  119. if(pos < list->size)

  120. {

  121. int i = 0;

  122. struct slist_node * p = list->head;

  123. for(; i < pos; i++)

  124. {

  125. p = p->next;

  126. }

  127. return p;

  128. }

  129.  
  130. return 0;

  131. }

  132.  
  133. static struct slist_node * _take_at(struct single_list * list, int pos)

  134. {

  135. if(pos < list->size)

  136. {

  137. int i = 0;

  138. struct slist_node * p = list->head;

  139. struct slist_node * prev = p;

  140. for(; i < pos ; i++)

  141. {

  142. prev = p;

  143. p = p->next;

  144. }

  145. if(p == list->head)

  146. {

  147. list->head = p->next;

  148. if(list->head == 0) list->tail = 0;

  149. }

  150. else if(p == list->tail)

  151. {

  152. list->tail = prev;

  153. prev->next = 0;

  154. }

  155. else

  156. {

  157. prev->next = p->next;

  158. }

  159.  
  160. list->size--;

  161.  
  162. p->next = 0;

  163. return p;

  164. }

  165.  
  166. return 0;

  167. }

  168.  
  169. static struct slist_node * _take_by_key(struct single_list * list, void *key)

  170. {

  171. if(list->key_hit_test)

  172. {

  173. struct slist_node * p = list->head;

  174. struct slist_node * prev = p;

  175. while(p)

  176. {

  177. if(list->key_hit_test(p, key) == 0) break;

  178. prev = p;

  179. p = p->next;

  180. }

  181.  
  182. if(p)

  183. {

  184. if(p == list->head)

  185. {

  186. list->head = p->next;

  187. if(list->head == 0) list->tail = 0;

  188. }

  189. else if(p == list->tail)

  190. {

  191. list->tail = prev;

  192. prev->next = 0;

  193. }

  194. else

  195. {

  196. prev->next = p->next;

  197. }

  198.  
  199. list->size--;

  200.  
  201. p->next = 0;

  202. return p;

  203. }

  204. }

  205. return 0;

  206. }

  207.  
  208. static struct single_list *_remove_node(struct single_list * list, struct slist_node * node)

  209. {

  210. struct slist_node * p = list->head;

  211. struct slist_node * prev = p;

  212. while(p)

  213. {

  214. if(p == node) break;

  215. prev = p;

  216. p = p->next;

  217. }

  218.  
  219. if(p)

  220. {

  221. if(p == list->head)

  222. {

  223. list->head = list->head->next;

  224. if(list->head == 0) list->tail = 0;

  225. }

  226. else if(p == list->tail)

  227. {

  228. prev->next = 0;

  229. list->tail = prev;

  230. }

  231. else

  232. {

  233. prev->next = p->next;

  234. }

  235.  
  236. if(list->free_node) list->free_node(p);

  237. else free(p);

  238.  
  239. list->size--;

  240. }

  241. return list;

  242. }

  243.  
  244. static struct single_list *_remove_at(struct single_list *list, int pos)

  245. {

  246. if(pos < list->size)

  247. {

  248. int i = 0;

  249. struct slist_node * p = list->head;

  250. struct slist_node * prev = p;

  251. for(; i < pos ; i++)

  252. {

  253. prev = p;

  254. p = p->next;

  255. }

  256. if(p == list->head)

  257. {

  258. list->head = p->next;

  259. if(list->head == 0) list->tail = 0;

  260. }

  261. else if(p == list->tail)

  262. {

  263. list->tail = prev;

  264. prev->next = 0;

  265. }

  266. else

  267. {

  268. prev->next = p->next;

  269. }

  270.  
  271. if(list->free_node) list->free_node(p);

  272. else free(p);

  273.  
  274. list->size--;

  275. }

  276.  
  277. return list;

  278. }

  279.  
  280. static struct single_list *_remove_by_key(struct single_list *list, void *key)

  281. {

  282. if(list->key_hit_test)

  283. {

  284. struct slist_node * p = list->head;

  285. struct slist_node * prev = p;

  286. while(p)

  287. {

  288. if(list->key_hit_test(p, key) == 0) break;

  289. prev = p;

  290. p = p->next;

  291. }

  292.  
  293. if(p)

  294. {

  295. if(p == list->head)

  296. {

  297. list->head = list->head->next;

  298. if(list->head == 0) list->tail = 0;

  299. }

  300. else if(p == list->tail)

  301. {

  302. prev->next = 0;

  303. list->tail = prev;

  304. }

  305. else

  306. {

  307. prev->next = p->next;

  308. }

  309.  
  310. if(list->free_node) list->free_node(p);

  311. else free(p);

  312.  
  313. list->size--;

  314. }

  315. }

  316.  
  317. return list;

  318. }

  319.  
  320. static int _length_of(struct single_list * list)

  321. {

  322. return list->size;

  323. }

  324.  
  325. static void _clear_list(struct single_list * list)

  326. {

  327. struct slist_node * p = list->head;

  328. struct slist_node * p2;

  329. while(p)

  330. {

  331. p2 = p;

  332. p = p->next;

  333.  
  334. if(list->free_node) list->free_node(p2);

  335. else free(p2);

  336. }

  337.  
  338. list->head = 0;

  339. list->tail = 0;

  340. list->size = 0;

  341. }

  342.  
  343. static void _delete_single_list(struct single_list *list)

  344. {

  345. list->clear(list);

  346. free(list);

  347. }

  348.  
  349. struct single_list * new_single_list(list_op_free_node op_free, list_op_key_hit_test op_cmp)

  350. {

  351. struct single_list *list = (struct single_list *)malloc(sizeof(struct single_list));

  352. list->head = 0;

  353. list->tail = 0;

  354. list->size = 0;

  355. list->free_node = op_free;

  356. list->key_hit_test = op_cmp;

  357.  
  358. list->add = _add_node;

  359. list->insert = _insert_node;

  360. list->replace = _replace;

  361. list->find_by_key = _find_by_key;

  362. list->first = _first_of;

  363. list->last = _last_of;

  364. list->at = _node_at;

  365. list->take_at = _take_at;

  366. list->take_by_key = _take_by_key;

  367. list->remove = _remove_node;

  368. list->remove_at = _remove_at;

  369. list->remove_by_key = _remove_by_key;

  370. list->length = _length_of;

  371. list->clear = _clear_list;

  372. list->deletor = _delete_single_list;

  373.  
  374. return list;

  375. }


    上面的代码就不一一细说了,下面是测试代码:

 
  1. /* call 1 or N arguments function of struct */

  2. #define ST_CALL(THIS,func,args...) ((THIS)->func(THIS,args))

  3.  
  4. /* call none-arguments function of struct */

  5. #define ST_CALL_0(THIS,func) ((THIS)->func(THIS))

  6.  
  7. struct int_node {

  8. struct slist_node node;

  9. int id;

  10. };

  11.  
  12. struct string_node {

  13. struct slist_node node;

  14. char name[16];

  15. };

  16.  
  17.  
  18. static int int_free_flag = 0;

  19. static void _int_child_free(struct slist_node *node)

  20. {

  21. free(node);

  22. if(!int_free_flag)

  23. {

  24. int_free_flag = 1;

  25. printf("int node free\n");

  26. }

  27. }

  28.  
  29. static int _int_slist_hittest(struct slist_node * node, void *key)

  30. {

  31. struct int_node * inode = NODE_T(node, struct int_node);

  32. int ikey = (int)key;

  33. return (inode->id == ikey ? 0 : 1);

  34. }

  35.  
  36. static int string_free_flag = 0;

  37. static void _string_child_free(struct slist_node *node)

  38. {

  39. free(node);

  40. if(!string_free_flag)

  41. {

  42. string_free_flag = 1;

  43. printf("string node free\n");

  44. }

  45. }

  46.  
  47. static int _string_slist_hittest(struct slist_node * node, void *key)

  48. {

  49. struct string_node * sn = (struct string_node*)node;

  50. return strcmp(sn->name, (char*)key);

  51. }

  52.  
  53. void int_slist_test()

  54. {

  55. struct single_list * list = new_single_list(_int_child_free, _int_slist_hittest);

  56. struct int_node * node = 0;

  57. struct slist_node * bn = 0;

  58. int i = 0;

  59.  
  60. printf("create list && nodes:\n");

  61. for(; i < 100; i++)

  62. {

  63. node = (struct int_node*)malloc(sizeof(struct int_node));

  64. node->id = i;

  65. if(i%10)

  66. {

  67. list->add(list, node);

  68. }

  69. else

  70. {

  71. list->insert(list, 1, node);

  72. }

  73. }

  74. printf("create 100 nodes end\n----\n");

  75. printf("first is : %d, last is: %d\n----\n",

  76. NODE_T( ST_CALL_0(list, first), struct int_node )->id,

  77. NODE_T( ST_CALL_0(list, last ), struct int_node )->id);

  78.  
  79. assert(list->size == 100);

  80.  
  81. printf("list traverse:\n");

  82. for(i = 0; i < 100; i++)

  83. {

  84. if(i%10 == 0) printf("\n");

  85. bn = list->at(list, i);

  86. node = NODE_T(bn, struct int_node);

  87. printf(" %d", node->id);

  88. }

  89. printf("\n-----\n");

  90.  
  91. printf("find by key test, key=42:\n");

  92. bn = list->find_by_key(list, (void*)42);

  93. assert(bn != 0);

  94. node = NODE_T(bn, struct int_node);

  95. printf("find node(key=42), %d\n------\n", node->id);

  96.  
  97. printf("remove node test, remove the 10th node:\n");

  98. bn = list->at(list, 10);

  99. node = NODE_T(bn, struct int_node);

  100. printf(" node 10 is: %d\n", node->id);

  101. printf(" now remove node 10\n");

  102. list->remove_at(list, 10);

  103. printf(" node 10 was removed, check node 10 again:\n");

  104. bn = list->at(list, 10);

  105. node = NODE_T(bn, struct int_node);

  106. printf(" now node 10 is: %d\n------\n", node->id);

  107.  
  108. printf("replace test, replace node 12 with id 1200:\n");

  109. bn = list->at(list, 12);

  110. node = NODE_T(bn, struct int_node);

  111. printf(" now node 12 is : %d\n", node->id);

  112. node = (struct int_node*)malloc(sizeof(struct int_node));

  113. node->id = 1200;

  114. list->replace(list, 12, node);

  115. bn = list->at(list, 12);

  116. node = NODE_T(bn, struct int_node);

  117. printf(" replaced, now node 12 is : %d\n----\n", node->id);

  118.  
  119. printf("test remove:\n");

  120. ST_CALL(list, remove, bn);

  121. bn = ST_CALL(list, find_by_key, (void*)1200);

  122. assert(bn == 0);

  123. printf("test remove ok\n----\n");

  124. printf("test remove_by_key(90):\n");

  125. ST_CALL(list, remove_by_key, (void*)90);

  126. bn = ST_CALL(list, find_by_key, (void*)90);

  127. assert(bn == 0);

  128. printf("test remove_by_key(90) end\n----\n");

  129. printf("test take_at(80):\n");

  130. bn = ST_CALL(list, take_at, 80);

  131. printf(" node 80 is: %d\n", NODE_T(bn, struct int_node)->id);

  132. free(bn);

  133. printf("test take_at(80) end\n");

  134.  
  135. int_free_flag = 0;

  136. printf("delete list && nodes:\n");

  137. list->deletor(list);

  138. printf("delete list && nodes end\n");

  139. printf("\n test add/insert/remove/delete/find_by_key/replace...\n");

  140. }

  141.  
  142. void string_slist_test()

  143. {

  144. struct single_list * list = new_single_list(_string_child_free, _string_slist_hittest);

  145. }

  146.  
  147. void slist_test()

  148. {

  149. int_slist_test();

  150. string_slist_test();

  151. }


    测试代码里主要演示了:

  • 自定义链表节点类型
  • 定义释放回调
  • 定义用于查找的 hit test 回调
  • 如何创建链表
  • 如何使用( add 、remove 、 take 、find 、 insert 等)

    相信到这里,单链表的使用已经不成问题了。

    以单链表为基础,可以进一步实现很多数据结构,比如树(兄弟孩子表示法),比如 key-value 链表等等。接下来根据例子的需要,会择机进行展示。

猜你喜欢

转载自blog.csdn.net/csshuke/article/details/82666202
今日推荐