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

  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内容如下:

  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.c内容如下:

  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前驱位置的值为%dn",GetItem(GetPrevious(p)));
  18. printf("p位置的值为%dn",GetItem(p));
  19. printf("p后继位置的值为%dn",GetItem(GetNext(p)));
  20.  
  21. printf("遍历输出各节点数据项:n");
  22. ListTraverse(plist,print);
  23. printf("除了头节点该链表共有%d个节点n",GetSize(plist));
  24. FreeNode(DelFirst(plist));
  25. printf("删除第一个节点后重新遍历输出为:n");
  26. ListTraverse(plist,print);
  27. printf("除了头节点该链表共有%d个节点n",GetSize(plist));
  28. DestroyList(plist);
  29. printf("链表已被销毁n");
  30. }

C语言一个双向链表的实现的更多相关文章

  1. C++语言实现双向链表

    这篇文章是关于利用C++模板的方式实现的双向链表以及双向链表的基本操作,在之前的博文C语言实现双向链表中,已经给大家分析了双向链表的结构,并以图示的方式给大家解释了双向链表的基本操作.本篇文章利用C+ ...

  2. C语言实现双向链表

    目前我们所学到的链表,无论是动态链表还是静态链表,表中各节点中都只包含一个指针(游标),且都统一指向直接后继节点,通常称这类链表为单向链表(或单链表). 虽然使用单链表能 100% 解决逻辑关系为 & ...

  3. 用C语言把双向链表中的两个结点交换位置,考虑各种边界问题。

    用C语言把双向链表中的两个结点交换位置,考虑各种边界问题. [参考] http://blog.csdn.net/silangquan/article/details/18051675

  4. Java实现一个双向链表的倒置功能

    题目要求:Java实现一个双向链表的倒置功能(1->2->3 变成 3->2->1) 提交:代码.测试用例,希望可以写成一个Java小项目,可以看到单元测试部分 该题目的代码, ...

  5. 跟踪LinkedList源码,通过分析双向链表实现原理,自定义一个双向链表

    1.LinkedList实现的基本原理 LinkedList是一个双向链表,它主要有两个表示头尾节点的成员变量first  .last,因其有头尾两个节点,所以从头或从尾操作数据都非常容易快捷.Lin ...

  6. C语言实现双向链表删除节点、插入节点、双向输出等操作

    #include<cstdio> #include<cstdlib> typedef struct DoubleLinkedList { int data; struct Do ...

  7. C语言数据结构----双向链表

    概括:主要说明双向链表的基本概念和具体操作以及源代码. 一.基本概念 1.有了单链表以后我们可以把内存中小块的空间联系在一起,并且把每一个小块都存储上我们想要存储的数值.但是单链表只有一个next,我 ...

  8. 大二作业——操作系统实验——C语言用双向链表,模拟实现动态分区式存储管理

    实验:动态分区式存储管理 实验内容: 编写程序模拟完成动态分区存储管理方式的内存分配和回收.实验具体包括:首先确定内存空闲分配表:然后采用最佳适应算法完成内存空间的分配和回收:最后编写主函数对所做工作 ...

  9. C语言-一个fopen函数中未使用二进制模式(b)引发的血案

    转自:http://blog.csdn.net/hinyunsin/article/details/6401854 最近写了一个网络文件传输模块,为了让这个模块具有更好的移植性,我尽量使用C标准IO ...

随机推荐

  1. 洛谷P2388 阶乘之乘

    题目背景 不告诉你-- 题目描述 求出1!*2!*3!*4!*--*n!的末尾有几个零 输入输出格式 输入格式: n(n<=10^8) 输出格式: 有几个零 输入输出样例 输入样例#1: 复制 ...

  2. POJ1509 Glass Beads

    Glass Beads Time Limit: 3000MS   Memory Limit: 10000K Total Submissions: 4314   Accepted: 2448 Descr ...

  3. [BZOJ]3527 力(ZJOI2014)

    第一次背出FFT模板,在此mark一道裸题. Description 给出n个数qi,给出Fj的定义如下: 令Ei=Fi/qi,求Ei. Input 第一行一个整数n. 接下来n行每行输入一个数,第i ...

  4. ubuntu 安装 WPS for Linux(ubuntu)字体配置(字体缺失解决办法)及卸载libreoffice

    从官网下载安装wps for Linux sudo dpkg -i wps-office_10.1.0.5672~a21_amd64.deb 启动WPS for Linux后,出现提示"系统 ...

  5. RHEL 7修改ssh默认端口号

    RHEL7修改默认端口号(默认port22)初次安装系统完毕后默认情况下系统已经启动了sshd服务当然我们也可以先进行检查: 步骤1,检查是否已安装ssh服务 步骤2,检查服务是否已开启 如上图所示显 ...

  6. vscode 搭建go开发环境的13个插件的安装

    由于网的问题 大家都不能直接go get 这里从易到难按难度给大家推荐几种方法 最简单的FQ 但是能FQ你还不能装 请问是假的FQ吗? 第一 用git 直接git反而能从那边趴下代码 但是要自己go ...

  7. Algorithm in Practice - Sorting and Searching

    Algorithm in Practice Author: Zhong-Liang Xiang Date: Aug. 1st, 2017 不完整, 部分排序和查询算法, 需添加. Prerequisi ...

  8. 如何搭建lamp(CentOS7+Apache+MySQL+PHP)环境

    我的环境:虚拟机是:VMware-workstation-full-8.0.0-471780.exe:Linux系统用的是:CentOS-7-x86_64-Minimal-1503-01.ios;(阿 ...

  9. 六星经典CSAPP-笔记(11)网络编程

    六星经典CSAPP-笔记(11)网络编程 参照<深入理解计算机系统>简单学习了下Unix/Linux的网络编程基础知识,进一步深入学习Linux网络编程和TCP/IP协议还得参考Steve ...

  10. 初识Spark2.0之Spark SQL

    内存计算平台spark在今年6月份的时候正式发布了spark2.0,相比上一版本的spark1.6版本,在内存优化,数据组织,流计算等方面都做出了较大的改变,同时更加注重基于DataFrame数据组织 ...