C语言---经典之双向链表的实现

更新时间:2018-06-29 15:38:05 点击次数:1361次

1、节点定义

typedef struct DListElement_

{

    void * data;
    struct DListElement_ *prev;
    struct DListElement_ *next;
}DListElement;

2、链表定义

typedef struct DList_
{
    int size;
    DListElement *head;
    DListElement *tail;
}Dlist;

3、从某个节点的头部插入

4、从某个节点的尾部插入

5、删除节点

int dlist_rm_node(Dlist *list, DListElement *element, void **data)

6、链表的遍历

int dlist_ergodic(Dlist *list)
{
    DListElement *p;
    p = list->head;
    while (p->next != NULL)
    {
        printf("%d-", (int)(p->data));
        p = p->next;
    }
    printf("%d-", (int)(p->data));
    printf("\n链表的长度为%d.\n", list->size);
    return;
}

首先编写头文件,头文件里做相关的定义和声明,DList.h内容如下:

[cpp] view plain copy
  1. #ifndef DList_H  
  2. #define DList_H  
  3. typedef  int Item;  
  4. typedef struct Node * PNode;  
  5. typedef PNode Position;  
  6. /*定义节点类型*/  
  7. typedef struct Node  
  8. {  
  9.     Item data;      /*数据域*/  
  10.     PNode previous; /*指向前驱*/  
  11.     PNode next;     /*指向后继*/  
  12. }Node;  
  13. /*定义链表类型*/  
  14. typedef struct  
  15. {  
  16.     PNode head;     /*指向头节点*/  
  17.     PNode tail;     /*指向尾节点*/  
  18.     int size;  
  19. }DList;  
  20.   
  21. /*分配值为i的节点,并返回节点地址*/  
  22. Position MakeNode(Item i);  
  23.   
  24. /*释放p所指的节点*/  
  25. void FreeNode(PNode p);  
  26.   
  27. /*构造一个空的双向链表*/  
  28. DList* InitList();  
  29.   
  30. /*摧毁一个双向链表*/  
  31. void DestroyList(DList *plist);  
  32.   
  33. /*将一个链表置为空表,释放原链表节点空间*/  
  34. void ClearList(DList *plist);  
  35.   
  36. /*返回头节点地址*/  
  37. Position GetHead(DList *plist);  
  38.   
  39. /*返回尾节点地址*/  
  40. Position GetTail(DList *plist);  
  41.   
  42. /*返回链表大小*/  
  43. int GetSize(DList *plist);  
  44.   
  45. /*返回p的直接后继位置*/  
  46. Position GetNext(Position p);  
  47.   
  48. /*返回p的直接前驱位置*/  
  49. Position GetPrevious(Position p);  
  50.   
  51. /*将pnode所指节点插入个节点之前*/  
  52. PNode InsFirst(DList *plist,PNode pnode);  
  53.   
  54. /*将链表个节点删除并返回其地址*/  
  55. PNode DelFirst(DList *plist);  
  56.   
  57. /*获得节点的数据项*/  
  58. Item GetItem(Position p);  
  59.   
  60. /*设置节点的数据项*/  
  61. void SetItem(Position p,Item i);  
  62.   
  63. /*删除链表中的尾节点并返回其地址,改变链表的尾指针指向新的尾节点*/  
  64. PNode Remove(DList *plist);  
  65.   
  66. /*在链表中p位置之前插入新节点S*/  
  67. PNode InsBefore(DList *plist,Position p,PNode s);  
  68.   
  69. /*在链表中p位置之后插入新节点s*/  
  70. PNode InsAfter(DList *plist,Position p,PNode s);  
  71.   
  72. /*返回在链表中第i个节点的位置*/  
  73. PNode LocatePos(DList *plist,int i);  
  74.   
  75. /*依次对链表中每个元素调用函数visit()*/  
  76. void ListTraverse(DList *plist,void (*visit)());  
  77. #endif  


接下来逐个实现其功能,DList.c内容如下:

[cpp] view plain copy
  1. #include"DList.h"  
  2. #include<malloc.h>  
  3. #include<stdlib.h>  
  4. /*分配值为i的节点,并返回节点地址*/  
  5. Position MakeNode(Item i)  
  6. {  
  7.     PNode p = NULL;   
  8.     p = (PNode)malloc(sizeof(Node));  
  9.     if(p!=NULL)  
  10.     {  
  11.         p->data = i;  
  12.         p->previous = NULL;  
  13.         p->next = NULL;  
  14.     }     
  15.     return p;  
  16. }  
  17. /*释放p所指的节点*/  
  18. void FreeNode(PNode p)  
  19. {  
  20.      free(p);  
  21. }  
  22. /*构造一个空的双向链表*/  
  23. DList * InitList()  
  24. {  
  25.     DList *plist = (DList *)malloc(sizeof(DList));  
  26.     PNode head = MakeNode(0);   
  27.     if(plist!=NULL)  
  28.     {  
  29.         if(head!=NULL)  
  30.         {  
  31.             plist->head = head;  
  32.             plist->tail = head;  
  33.             plist->size = 0;  
  34.         }  
  35.         else  
  36.             return NULL;  
  37.     }  
  38.     return plist;  
  39. }  
  40.   
  41. /*摧毁一个双向链表*/  
  42. void DestroyList(DList *plist)  
  43. {  
  44.     ClearList(plist);  
  45.     free(GetHead(plist));  
  46.     free(plist);  
  47. }  
  48.   
  49. /*判断链表是否为空表*/  
  50. int IsEmpty(DList *plist)  
  51. {  
  52.     if(GetSize(plist)==0&&GetTail(plist)==GetHead(plist))  
  53.         return 1;  
  54.     else  
  55.         return 0;  
  56. }  
  57. /*将一个链表置为空表,释放原链表节点空间*/  
  58. void ClearList(DList *plist)  
  59. {  
  60.     PNode temp,p;  
  61.     p = GetTail(plist);  
  62.     while(!IsEmpty(plist))  
  63.     {     
  64.         temp = GetPrevious(p);  
  65.         FreeNode(p);  
  66.         p = temp;  
  67.         plist->tail = temp;  
  68.         plist->size--;  
  69.     }  
  70. }  
  71.   
  72. /*返回头节点地址*/  
  73. Position GetHead(DList *plist)  
  74. {  
  75.     return plist->head;  
  76. }  
  77.   
  78. /*返回尾节点地址*/  
  79. Position GetTail(DList *plist)  
  80. {  
  81.     return plist->tail;  
  82. }  
  83.   
  84. /*返回链表大小*/  
  85. int GetSize(DList *plist)  
  86. {  
  87.     return plist->size;  
  88. }  
  89.   
  90. /*返回p的直接后继位置*/  
  91. Position GetNext(Position p)  
  92. {  
  93.     return p->next;  
  94. }  
  95.   
  96. /*返回p的直接前驱位置*/  
  97. Position GetPrevious(Position p)  
  98. {  
  99.     return p->previous;  
  100. }  
  101.   
  102. /*将pnode所指节点插入个节点之前*/  
  103. PNode InsFirst(DList *plist,PNode pnode)  
  104. {  
  105.     Position head = GetHead(plist);  
  106.   
  107.     if(IsEmpty(plist))  
  108.         plist->tail = pnode;  
  109.     plist->size++;  
  110.   
  111.     pnode->next = head->next;  
  112.     pnode->previous = head;  
  113.   
  114.     if(head->next!=NULL)  
  115.         head->next->previous = pnode;  
  116.     head->next = pnode;  
  117.       
  118.     return pnode;   
  119. }  
  120.   
  121. /*将链表个节点删除,返回该节点的地址*/  
  122. PNode DelFirst(DList *plist)  
  123. {  
  124.     Position head = GetHead(plist);  
  125.     Position p=head->next;  
  126.     if(p!=NULL)  
  127.     {  
  128.         if(p==GetTail(plist))  
  129.             plist->tail = p->previous;  
  130.         head->next = p->next;  
  131.         head->next->previous = head;  
  132.         plist->size--;  
  133.           
  134.     }     
  135.     return p;  
  136. }  
  137.   
  138. /*获得节点的数据项*/  
  139. Item GetItem(Position p)  
  140. {  
  141.     return p->data;  
  142. }  
  143.   
  144. /*设置节点的数据项*/  
  145. void SetItem(Position p,Item i)  
  146. {  
  147.     p->data = i;  
  148. }  
  149.   
  150. /*删除链表中的尾节点并返回地址,改变链表的尾指针指向新的尾节点*/  
  151. PNode Remove(DList *plist)  
  152. {  
  153.     Position p=NULL;  
  154.     if(IsEmpty(plist))  
  155.         return NULL;  
  156.     else  
  157.     {  
  158.         p = GetTail(plist);  
  159.         p->previous->next = p->next;  
  160.         plist->tail = p->previous;  
  161.         plist->size--;  
  162.         return p;  
  163.     }  
  164. }  
  165. /*在链表中p位置之前插入新节点s*/  
  166. PNode InsBefore(DList *plist,Position p,PNode s)  
  167. {  
  168.     s->previous = p->previous;  
  169.     s->next = p;  
  170.     p->previous->next = s;      
  171.     p->previous = s;  
  172.   
  173.     plist->size++;  
  174.     return s;  
  175. }  
  176. /*在链表中p位置之后插入新节点s*/  
  177. PNode InsAfter(DList *plist,Position p,PNode s)  
  178. {  
  179.     s->next = p->next;  
  180.     s->previous = p;  
  181.       
  182.     if(p->next != NULL)  
  183.         p->next->previous = s;  
  184.     p->next = s;  
  185.       
  186.     if(p = GetTail(plist))  
  187.         plist->tail = s;  
  188.       
  189.     plist->size++;  
  190.     return s;  
  191. }  
  192.   
  193. /*返回在链表中第i个节点的位置*/  
  194. PNode LocatePos(DList *plist,int i)  
  195. {  
  196.     int cnt = 0;  
  197.     Position p = GetHead(plist);  
  198.     if(i>GetSize(plist)||i<1)  
  199.         return NULL;  
  200.   
  201.     while(++cnt<=i)  
  202.     {  
  203.         p=p->next;  
  204.     }  
  205.   
  206.     return p;  
  207. }  
  208.   
  209. /*依次对链表中每个元素调用函数visit()*/  
  210. void ListTraverse(DList *plist,void (*visit)())  
  211. {  
  212.     Position p = GetHead(plist);  
  213.     if(IsEmpty(plist))  
  214.         exit(0);  
  215.     else  
  216.     {  
  217.           
  218.         while(p->next!=NULL)  
  219.         {  
  220.             p = p->next;  
  221.             visit(p->data);            
  222.         }         
  223.     }  
  224. }  


接下来进行测试,Test.h内容如下:

[cpp] view plain copy
  1. #include"DList.h"  
  2. #include<stdio.h>  
  3. void print(Item i)  
  4. {  
  5.     printf("数据项为%d \n",i);  
  6. }  
  7. main()  
  8. {  
  9.     DList *plist = NULL;  
  10.     PNode p = NULL;  
  11.       
  12.     plist = InitList();  
  13.     p = InsFirst(plist,MakeNode(1));  
  14.     InsBefore(plist,p,MakeNode(2));  
  15.     InsAfter(plist,p,MakeNode(3));  
  16.   
  17.     printf("p前驱位置的值为%d\n",GetItem(GetPrevious(p)));  
  18.     printf("p位置的值为%d\n",GetItem(p));  
  19.     printf("p后继位置的值为%d\n",GetItem(GetNext(p)));  
  20.       
  21.       
  22.     printf("遍历输出各节点数据项:\n");  
  23.     ListTraverse(plist,print);  
  24.     printf("除了头节点该链表共有%d个节点\n",GetSize(plist));  
  25.     FreeNode(DelFirst(plist));  
  26.     printf("删除个节点后重新遍历输出为:\n");  
  27.     ListTraverse(plist,print);  
  28.     printf("除了头节点该链表共有%d个节点\n",GetSize(plist));  
  29.     DestroyList(plist);  
  30.     printf("链表已被销毁\n");  
  31. }  

本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是一个个人学习交流的平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽,造成漏登,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

回到顶部
嘿,我来帮您!