C 算法精介----链表(1)

C算法 ---链表

转载于http://blog.youkuaiyun.com/jsh13417/article/details/8297093?reload

链表是一种最为基础的数据结构,链表是由一组元素以一种特定的顺序组合或链接在一起的。在维护数据的集合时很有用途。在平时的数据处理过程中经常会会用链接进行数据的临时存储。但是如何才能使链表处理数据更加优化,下面简单介绍单链表处理情况!

1 、单链表介绍

单链表是各个元素之间通过一个指针彼此连接起来而组成的。元素可以分为2个部分:数据成员和一个称为nest的指针。通过这种2成员结构,将每个元素的next指针指向其元素后面的指针。为了更能描述这种结构可以看下图:

要访问链表中的元素,从链表的头部开始,通过next指针从一个元素到另一个元素。然而每个元素的都需要动态的申请和释放空间。元素和元素之间的连接关系可以确保每个元素都能够访问到。因为在对数据处理时,一定要特别的小心。如果中间丢失掉一个元素,后面的就无法访问到。

2 单链表的实现和分析

示例1 链表抽象的数据类型的头文件

  1. #ifndef LIST_H
  2. #define LIST_H
  3. #include <stdlib.h>
  4. /*define a structure for linked List elements */
  5. typedef struct ListElmt_{
  6. void *data;
  7. struct ListElmt_ *next;
  8. }ListElmt;
  9. /*define a structure for linked lists */
  10. typedef struct List_ {
  11. int size;
  12. int (*match)(constvoid * key1,constvoid * key2);
  13. void (*destroy)(void *data);
  14. ListElmt *head;
  15. ListElmt *tail;
  16. }List;
  17. /*Public Intefaces */
  18. void list_init(List *list,void (*destroy)(void *data));
  19. void list_destory(List *list);
  20. int list_ins_next(List *list, ListElmt *element,constvoid *data);
  21. int list_rem_next(List *list, ListElmt *element,void *data);
  22. #define list_size(list) ((list) -> size)
  23. #define list_head(list) ((list) -> head)
  24. #define list_tail(list) ((list) -> tail)
  25. #define list_is_head(list, element) ((element) == (list) -> head ? 1:0)
  26. #define list_is_tail(list, element) ((element) == (list) -> tail ? 1:0)
  27. #define list_data(element) ((element) -> data)
  28. #define list_next(element) ((element) -> next)
  29. #endif
 
示例2 链表抽象数据类型的实现
  1. #include <studio.h>
  2. #include <string.h>
  3. #include "../include/List.h"
  4. /*list_init */
  5. void list_init(List * list,void(* destroy)(void * data)) {
  6. /* initialize the list */
  7. list -> size = 0;
  8. list -> destroy = destroy;
  9. list -> head = NULL;
  10. list -> tail = NULL;
  11. return ;
  12. }
  13. /*list_destroy */
  14. void list_destory(List * list) {
  15. void *data;
  16. /*Remove eah element */
  17. while (list_size(list) > 0){
  18. if (list_rem_next(list, NULL, (void **) &data) == 0 && list -> destroy
  19. != NULL){
  20. /* Call a user-defined function to free dynamically allocated data*/
  21. list -> destroy(data);
  22. }
  23. }
  24. memset(list, 0, sizeof(List));
  25. return;
  26. }
  27. /*list_ins_nest */
  28. int list_ins_next (List * list, ListElmt * element,constvoid * data){
  29. ListElmt *new_element;
  30. /* Allocate storage for the element */
  31. if ((new_element = (ListElmt *)malloc(sizeof(ListElmt))) == NULL){
  32. return -1;
  33. }
  34. /*insert the element into the list */
  35. new_element ->data =(void *)data;
  36. if (element == NULL){
  37. /* handle insertion at the head of the list */
  38. if (list_size(list) == 0){
  39. list -> tail = new_element;
  40. }
  41. new_element ->next = list ->head;
  42. list -> head = new_element;
  43. } else {
  44. /*Handle insertion somewhere other than at the head */
  45. if (element ->next == NULL ){
  46. list ->tail = new_element;
  47. }
  48. new_element ->next = element ->next;
  49. element->next = new_element;
  50. }
  51. list->size ++;
  52. return 0;
  53. }
  54. /* list_rem_next */
  55. int list_rem_next(List * list, ListElmt * element,void * data) {
  56. ListElmt *old_element;
  57. /* Do not allow removal from an emptry list */
  58. if (list_size(list) == 0){
  59. return -1;
  60. }
  61. /* romove the element from the list */
  62. if (element == NULL){
  63. /* handle removel from the head of the list */
  64. *data = list->head->data;
  65. old_element = list ->head;
  66. list->head = list -> head->next;
  67. if (list_size(list) == 1){
  68. list->tail = NULL;
  69. }
  70. } else {
  71. /* handle removal from somewhere other than the head */
  72. if ( element->next == NULL){
  73. return -1;
  74. }
  75. *data = element->next->data;
  76. old_element = element->next;
  77. element->next = element->next->next;
  78. if (element ->next == NULL){
  79. list->tail = NULL;
  80. }
  81. }
  82. /* free the storage allocated by the abstract datatype*/
  83. free(old_element);
  84. list->size --;
  85. return 0;
  86. }

  87. 3 下面对几个重要的函数接口实现进行介绍

list_init

list_init用来初始化一个链表仪表能够执行其他的操作,主要成员的描述:

size:链表中元素的个数;初始化为0;

destroy:定义的一个析构函数(http://baike.baidu.com/view/1277985.htm);初始换有函数参数传入;

head和tail:2个指针主要表头和表尾。初始化为NULL;

list_destroy

list_destroy 用来销毁链表,也就是取出链表中的所有函数;

函数主要是循环判断size,直到size为0时退出。函数的实现是调用函数list_rem_next,第二个参数为NULL时,表示,从第一个元素开始删除。如果析构函数不为NULL,则应该调用析构函数。

list_ins_next

list_ins_next 将一个元素插入有element指定的元素之后。新元素的数据只想由用户传入的数据。想链表中插入数据要有2中情况要考虑:插入头或其他位置,具体参照函数的实现。当传入参数element为NULL,表示从插入到表头;

list_rem_next

list_rem_next 从链表中移除指定元素之后的那个节点,并将其保存的数据保存的参数data中;同样也需要考虑2中情况:删除头或者其他位置的。当参数element为NULL时,表示从表头删除!

4 双向链表

双向链表,如同名字所暗示的那样,链表元素之间由2个指针链接,双向链表中的每一个元素都有3部分组成:除了数据成员和指针next外,新增加了一个指针prev,指向其前驱元素的指针。下图清晰绘出双向链表的结构:

双向链表的实现和分析

  1. #ifndef DLIST_H
  2. #define DLIST_H
  3. #include <stdlib.h>
  4. /*define a structure for doubly-linked list elements */
  5. typedef struct DlistElmt_ {
  6. void *data;
  7. struct DlistElmt_ *prev;
  8. struct DlistElmt_ *next;
  9. }DlistElmt;
  10. /*define a structure for doubly-linked lists */
  11. typedef struct Dlist_ {
  12. int size;
  13. int (*match)(constvoid *key1,constvoid * key2);
  14. void (*destroy)(void *data);
  15. DlistElmt *head;
  16. DlistElmt *tail;
  17. }Dlist;
  18. /*Public Intefaces */
  19. void dlist_init(Dlist *dlist,void (*destroy)(void *data));
  20. void dlist_destory(Dlist *dlist);
  21. int dlist_ins_next(Dlist *dlist, DlistElmt *element,constvoid *data);
  22. int dlist_ins_prev(Dlist *dlist, DlistElmt *element,constvoid *data);
  23. int dlist_remove(Dlist *dlist, DlistElmt *element,void *data);
  24. #define dlist_size(dlist) ((dlist) ->size)
  25. #define dlist_head(dlist) ((dlist) ->head)
  26. #define dlist_tail(dlist) ((dlist) ->tail)
  27. #define dlist_is_head(element) ((element) ->prev == NULL? 1:0)
  28. #define dlist_is_tail(element) ((element) ->next == NULL ? 1:0)
  29. #define dlist_data(element) ((element) ->data)
  30. #define dlist_next(element) ((element) ->next)
  31. #define dlist_prev(element) ((element)->prev)
  32. #endif


  1. /* dlist.c */
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "../include/Dlist.h"
  5. /*dlist_init */
  6. void dlist_init(Dlist * dlist,void(* destroy)(void * data)){
  7. /* initialize the list */
  8. list -> size = 0;
  9. list -> destroy = destroy;
  10. list -> head = NULL;
  11. list -> tail = NULL;
  12. return ;
  13. }
  14. /*list_destroy */
  15. void dlist_destory(Dlist * dlist){
  16. void *data;
  17. /*Remove eah element */
  18. while (dlist_size(dlist) > 0){
  19. if (dlist_remove(dlist, dlist_tail(dlist), (void **) &data) == 0 && dlist -> destroy
  20. != NULL){
  21. /* Call a user-defined function to free dynamically allocated data*/
  22. dlist ->destroy(data);
  23. }
  24. }
  25. memset(dlist, 0, sizeof(Dlist));
  26. return;
  27. }
  28. /*dlist_destroy */
  29. void dlist_destory(Dlist * dlist) {
  30. void *data;
  31. /* remove each element */
  32. while (dlist_size(dlist) > 0){
  33. if (dlist_remove(Dlist * dlist, dlist_tail(dlist),void * data) == 0 &&
  34. dlist->destroy != NULL){
  35. /* call a user-defined function to free dynamically allocated data */
  36. dlist->destroy(data);
  37. }
  38. }
  39. memset(list,0,sizeof(Dlist));
  40. return;
  41. }
  42. /* dlist_ins_next */
  43. int dlist_ins_next(Dlist * dlist, DlistElmt * element,constvoid * data){
  44. DlistElmt *new_element;
  45. /* do not allow a NULL element unless dlist is empty*/
  46. if (element == NULL && dlist_size(dlist) == 0){
  47. return -1;
  48. }
  49. /* allocate storage for the element */
  50. if ((new_element = (DlistElmt *)malloc(sizeof(DlistElmt))) == NULL){
  51. return -1;
  52. }
  53. new_element->data = (void *) data;
  54. if (dlist_size(dlist) == 0){
  55. dlist->head = new_element;
  56. new_element->prev = NULL;
  57. new_element->next = NULL;
  58. dlist->tail = new_element;
  59. } else {
  60. new_element->next = element->next;
  61. new_element->prev = element;
  62. if (element->next == NULL){
  63. dlist->tail = new_element;
  64. } else {
  65. element->next->prev = new_element;
  66. }
  67. element->next = new_element;
  68. }
  69. dlist->size++;
  70. return 0;
  71. }
  72. int dlist_ins_prev(Dlist * dlist, DlistElmt * element,constvoid * data){
  73. DlistElmt *new_element;
  74. /* do not allow a NULL element unless dlist is empty*/
  75. if (element == NULL && dlist_size(dlist) == 0){
  76. return -1;
  77. }
  78. /* allocate storage for the element */
  79. if ((new_element = (DlistElmt *)malloc(sizeof(DlistElmt))) == NULL){
  80. return -1;
  81. }
  82. new_element->data = (void *) data;
  83. if (dlist_size(dlist) == 0){
  84. dlist->head = new_element;
  85. new_element->prev = NULL;
  86. new_element->next = NULL;
  87. dlist->tail = new_element;
  88. } else {
  89. new_element->next = element;
  90. new_element->prev = element->prev;
  91. if (element== NULL){
  92. dlist->tail = new_element;
  93. } else {
  94. element->prev->next= new_element;
  95. }
  96. element->prev = new_element;
  97. }
  98. dlist->size++;
  99. return 0;
  100. }
  101. int dlist_remove(Dlist * dlist, DlistElmt * element,void * data) {
  102. /*do not allow a NULL element or removal from an empty list */
  103. if (element == NULL || dlist_size(dlist) == 0){
  104. return -1;
  105. }
  106. /* Remove the element from the list */
  107. *data = element->data;
  108. if (element == dlist->head){
  109. /*handle removal from the head of the list */
  110. dlist->head = element->next;
  111. if (dlist->head ==NULL){
  112. dlist->tail = NULL;
  113. } else {
  114. element->next->prev = NULL;
  115. }
  116. } else {
  117. element->prev->next = element ->next;
  118. if (element->next == NULL){
  119. dlist->tail = element->prev;
  120. } else {
  121. element ->next->prev = element->prev;
  122. }
  123. }
  124. free(element);
  125. dlist->size--
  126. return 0;
  127. }


以上便是双向链表的函数实现过程,具体就不在分析了,和单向链表差不多!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值