http://blog.csdn.net/fisherwan/article/details/19801993

双向循环链表是基于双向链表的基础上实现的,和双向链表的操作差不多,唯一的区别就是它是个循环的链表,通过每个节点的两个指针把它们扣在一起组成一个环状。所以呢,每个节点都有前驱节点和后继节点(包括头节点和尾节点)这是和双向链表不同的地方。我们看下双向循环链表的示意图(我在网上找了张图片,自己画的实在难看,有时间真的要去学下怎么画图了,然后可以写出更好的博客):

在程序的编写方面呢,双向循环链表有点向前面知识的组合,双向循环链表在“双向”方面和双向链表一样,在“循环方面”和单向循环链表一样。以前的知识消化了呢,这个双向循环链表也就简单了。上面这个图比较形象的体现出了双向循环链表的含义:简单说呢,就是当前节点的一个指针指向前置节点一个指针指向后继节点,每个节点都重复这样,就形成了一个环了。

DbCcLinkList.h 头文件——包含了节点结构的定义和链表相关操作函数的声明

[cpp] view plain copy
  1. #ifndef DOUBLE_CIRCULAR_LINKED_LIST_H
  2. #define DOUBLE_CIRCULAR_LINKED_LIST_H
  3. typedef struct Node
  4. {
  5. int data;
  6. struct Node *pNext;
  7. struct Node *pPre;
  8. }NODE, *pNODE;
  9. //创建双向循环链表
  10. pNODE CreateDbCcLinkList(void);
  11. //打印链表
  12. void TraverseDbCcLinkList(pNODE pHead);
  13. //判断链表是否为空
  14. int IsEmptyDbCcLinkList(pNODE pHead);
  15. //计算链表的长度
  16. int GetLengthDbCcLinkList(pNODE pHead);
  17. //向链表中插入节点
  18. int InsertEleDbCcLinkList(pNODE pHead, int pos, int data);
  19. //从链表中删除节点
  20. int DeleteEleDbCcLinkList(pNODE pHead, int pos);
  21. //删除整个链表,释放内存
  22. void FreeMemory(pNODE *ppHead);
  23. #endif

DbCcLinkList.cpp 双向循环链表的源文件——包含了链表相关操作函数的定义

(1)这部分是用来创建链表的,双向循环链表每插入一个节点就要控制4个指针,第一,插入位置的上一个节点有一个指针,它要指向插入节点;第二,插入的节点有两个指针,一个指向上一个节点,一个指向下一个节点;第三,插入位置的下一个节点有一个指针,它是指着插入节点的。写程序的关键也就是控制好这四个指针,不要弄错了,要不然会有奇怪的结果(程序出不来结果,无线循环等)

[cpp] view plain copy
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "DbCcLinkList.h"
  4. //创建双向循环链表
  5. pNODE CreateDbCcLinkList(void)
  6. {
  7. int i, length = 0, data = 0;
  8. pNODE p_new = NULL, pTail = NULL;
  9. pNODE pHead = (pNODE)malloc(sizeof(NODE));
  10. if (NULL == pHead)
  11. {
  12. printf("内存分配失败!\n");
  13. exit(EXIT_FAILURE);
  14. }
  15. pHead->data = 0;
  16. pHead->pNext = pHead;
  17. pHead->pPre = pHead;
  18. pTail = pHead;
  19. printf("请输入想要创建链表的长度:");
  20. scanf("%d", &length);
  21. for (i=1; i<length+1; i++)
  22. {
  23. p_new = (pNODE)malloc(sizeof(NODE));
  24. if (NULL == p_new)
  25. {
  26. printf("内存分配失败!\n");
  27. exit(EXIT_FAILURE);
  28. }
  29. printf("请输入第%d个节点元素值:", i);
  30. scanf("%d", &data);
  31. p_new->data = data;
  32. p_new->pPre = pTail;
  33. p_new->pNext = pHead;
  34. pTail->pNext = p_new;
  35. pHead->pPre = p_new;
  36. pTail = p_new;
  37. }
  38. return pHead;
  39. }

(2)这部分是获得双向链表的信息,和单向循环链表一样,链表结束的限制条件是判断是否等于头结点。意思就是从头节点的下一个节点开始如果又到了头节点说明已经遍历一圈了。

[cpp] view plain copy
  1. //打印链表
  2. void TraverseDbCcLinkList(pNODE pHead)
  3. {
  4. pNODE pt = pHead->pNext;
  5. printf("链表打印如:");
  6. while (pt != pHead)
  7. {
  8. printf("%d ", pt->data);
  9. pt = pt->pNext;
  10. }
  11. putchar('\n');
  12. }
  13. //判断链表是否为空
  14. int IsEmptyDbCcLinkList(pNODE pHead)
  15. {
  16. pNODE pt = pHead->pNext;
  17. if (pt == pHead)
  18. return 1;
  19. else
  20. return 0;
  21. }
  22. //计算链表的长度
  23. int GetLengthDbCcLinkList(pNODE pHead)
  24. {
  25. int length = 0;
  26. pNODE pt = pHead->pNext;
  27. while (pt != pHead)
  28. {
  29. length++;
  30. pt = pt->pNext;
  31. }
  32. return length;
  33. }

(3)这部分是双向链表的插入、删除节点操作, 但是它不需要和双向链表一样判断最后一个节点是否为空(因为此时要用到节点的指针),双向循环链表不存在这样的情况,这是由于它不光是双向的,而且是循环的,所以每个节点都不可能为空。

[cpp] view plain copy
  1. //向链表中插入节点
  2. int InsertEleDbCcLinkList(pNODE pHead, int pos, int data)
  3. {
  4. pNODE p_new = NULL, pt = NULL;
  5. if (pos > 0 && pos < GetLengthDbCcLinkList(pHead) + 2)
  6. {
  7. p_new = (pNODE)malloc(sizeof(NODE));
  8. if (NULL == p_new)
  9. {
  10. printf("内存分配失败!\n");
  11. exit(EXIT_FAILURE);
  12. }
  13. while (1)
  14. {
  15. pos--;
  16. if (0 == pos)
  17. break;
  18. pHead = pHead->pNext;
  19. }
  20. p_new->data = data;
  21. pt = pHead->pNext;
  22. p_new->pNext = pt;
  23. p_new->pPre = pHead;
  24. pHead->pNext = p_new;
  25. pt->pPre = p_new;
  26. return 1;
  27. }
  28. else
  29. return 0;
  30. }
  31. //从链表中删除节点
  32. int DeleteEleDbCcLinkList(pNODE pHead, int pos)
  33. {
  34. pNODE pt = NULL;
  35. if (pos > 0 && pos < GetLengthDbCcLinkList(pHead) + 1)
  36. {
  37. while (1)
  38. {
  39. pos--;
  40. if (0 == pos)
  41. break;
  42. pHead = pHead->pNext;
  43. }
  44. pt = pHead->pNext->pNext;
  45. free(pHead->pNext);
  46. pHead->pNext = pt;
  47. pt->pPre = pHead;
  48. return 1;
  49. }
  50. else
  51. return 0;
  52. }

(4)这是释放内存操作,和上面讲的一样,不需要判断最后一个节点是否为空,每次释放一个节点的内存的以后它还是保持环状的结构,所以没有节点为空。

[cpp] view plain copy
  1. //删除整个链表,释放内存空间
  2. void FreeMemory(pNODE *ppHead)
  3. {
  4. pNODE pt = NULL;
  5. while (*ppHead != NULL)
  6. {
  7. pt = (*ppHead)->pNext->pNext;
  8. if ((*ppHead)->pNext == *ppHead)
  9. {
  10. free(*ppHead);
  11. *ppHead = NULL;
  12. }
  13. else
  14. {
  15. free((*ppHead)->pNext);
  16. (*ppHead)->pNext = pt;
  17. pt->pPre = *ppHead;
  18. }
  19. }
  20. }

maincpp 测试程序——通过简单的交互界面判断函数的功能是否正确

[cpp] view plain copy
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "DbCcLinkList.h"
  4. int main(void)
  5. {
  6. int flag = 0, length = 0;
  7. int position = 0, value = 0;
  8. pNODE head = NULL;
  9. head = CreateDbCcLinkList();
  10. flag = IsEmptyDbCcLinkList(head);
  11. if (flag)
  12. printf("双向循环链表为空!\n");
  13. else
  14. {
  15. length = GetLengthDbCcLinkList(head);
  16. printf("双向循环链表的长度为:%d\n", length);
  17. TraverseDbCcLinkList(head);
  18. }
  19. printf("请输入要插入节点的位置和元素值(两个数用空格隔开):");
  20. scanf("%d %d", &position, &value);
  21. flag = InsertEleDbCcLinkList(head, position, value);
  22. if (flag)
  23. {
  24. printf("插入节点成功!\n");
  25. TraverseDbCcLinkList(head);
  26. }
  27. else
  28. printf("插入节点失败!\n");
  29. flag = IsEmptyDbCcLinkList(head);
  30. if (flag)
  31. printf("双向循环链表为空,不能进行删除操作!\n");
  32. else
  33. {
  34. printf("请输入要删除节点的位置:");
  35. scanf("%d", &position);
  36. flag = DeleteEleDbCcLinkList(head, position);
  37. if (flag)
  38. {
  39. printf("删除节点成功!\n");
  40. TraverseDbCcLinkList(head);
  41. }
  42. else
  43. printf("删除节点失败!\n");
  44. }
  45. FreeMemory(&head);
  46. if (NULL == head)
  47. printf("已成功删除双向循环链表,释放内存完成!\n");
  48. else
  49. printf("删除双向循环链表失败,释放内存未完成!\n");
  50. return 0;
  51. }

PS:到这里为止,链表的知识就写到这里了,后面开始就是队列和栈了。其实线性表方面的知识都大同小异,只要原理清楚之后,它的形式的变化可以是多钟多样的,当然本人水平有限,希望能和同道之人继续深入探讨,共同进步。

(C语言版)链表(四)——实现双向循环链表创建、插入、删除、释放内存等简单操作相关推荐

  1. (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作

    http://blog.csdn.net/fisherwan/article/details/19760681 上午写了下单向循环链表的程序,今天下午我把双向链表的程序写完了.其实双向链表和单向链表也 ...

  2. (C语言版)链表(二)——实现单向循环链表创建、插入、删除、释放内存等简单操作

    http://blog.csdn.net/fisherwan/article/details/19754585 昨天写了单向链表的代码,今天上午把单向循环链表的程序给敲完了.链表的相关操作一样的,包含 ...

  3. 双向循环链表的插入与删除

    关于解释部分不再多说了,网上资料很多,下面就介绍具体的实现吧 //双向循环链表的插入与删除 typedef struct node{     int data;     struct node *pr ...

  4. (C++版)链表(四)——实现双向循环链表创建、插入、删除等简单操作

    http://blog.csdn.net/fisherwan/article/details/25649271 链表(四)实现双向循环链表简单操作,代码如下: [cpp] view plain cop ...

  5. 【数据结构】链表:带头双向循环链表的增删查改

    本篇要分享的内容是带头双向链表,以下为本片目录 目录 一.链表的所有结构 二.带头双向链表 2.1尾部插入 2.2哨兵位的初始化 2.3头部插入 2.4 打印链表 2.5尾部删除 2.6头部删除 2. ...

  6. 数据结构c语言版第四章题库,数据结构(C语言版)(第4版)习题

    数据结构(C语言版)(第4版)习题 习题 11.1 选择题.(1)计算机识别.存储和加工处理的对象统称为 .A.数据 B.数据元素 C.数据结构 D.数据类型(2)数据结构通常是研究数据的 及它们之间 ...

  7. 数据结构c语言版第四章题库,严蔚敏《数据结构(c语言版)习题集》答案第四章 串...

    严蔚敏<数据结构(c语言版)习题集>答案第四章 串 第四章 串 4.10 void String_Reverse(Stringtype s,Stringtype &r)//求s的逆 ...

  8. 《数据结构》C语言版 链表的基本操作实现

    #include <stdio.h> #include <stdlib.h>#define ok 1 #define error -1typedef int ElemType; ...

  9. 数据结构:带头双向循环链表——增加、删除、查找、修改,详细解析

    读者可以先阅读这一篇:数据结构--单链表的增加.删除.查找.修改,详细解析_昵称就是昵称吧的博客-CSDN博客,可以更好的理解带头双向循环链表. 目录 一.带头双向循环链表的处理和介绍 1.带头双向循 ...

最新文章

  1. Kubernetes学习笔记---常用命令
  2. 详解在visual studio中使用git版本系统(图文)
  3. 当AV1视频编解码器来到Webex!
  4. javaweb学习总结(十四):JSP原理
  5. MySQL使用二进制日志恢复数据库
  6. 图解LinkedHashMap原理
  7. win7无法连接打印机拒绝访问_Win7系统”windows无法连接到打印机拒绝访问“怎么办?通过创建local port端口连接来搞定...
  8. Mac备忘录笔记教学——强大的内置笔记软件
  9. Spring Data Jpa使用@Query时 报错Validation failed for query for method public abstract
  10. 存储器——存储器容量扩充
  11. 网易云音乐 网络错误 linux,在Linux下网易云音乐打不开的另一种解决方法
  12. 去除最新版WinRAR的弹窗广告
  13. c语言表白情书作品,程序员一句话表白情书
  14. 删除后别人的微信号变成wxid_如何找回已删除的微信好友?卓师兄神助攻
  15. OneZero第四周第一次站立会议(2016.4.11)
  16. niushop多商户商户端手机uniapp源码v4单商户v4_Saas开源版含uniapp以及niushop社区团购标准版源码开源的区别
  17. 古训《增广贤文》补遗
  18. java门禁系统项目开发实现
  19. 如何快速地向服务器传大文件,大文件如何快速传输
  20. 两年经验斩获蚂蚁/头条/PingCAP Offer,牛逼了

热门文章

  1. 字符串匹配(KMP 算法 含代码)
  2. java如何从方法返回多个值
  3. android unbound prefix
  4. dnse 2.0音效厉害还是full sound厉害点呢?谢谢!!
  5. linux用户操作的日志,linux 用户操作记录并录入日志
  6. Linux装ntfs后内存不够,Linux_安装Ubuntu后无法使用NTFS硬盘或移动硬盘,  在安装Ubuntu系统后,存在 - phpStudy...
  7. java能不能修改文件大小信息_java上机考试3
  8. 小学计算机技术指导纲要,《中小学信息技术课程指导纲要(试行)》
  9. vs2019 缺android sdk,VS2019由于缺少NuGet Microsoft.NET.Sdk.Functions程序包而无法加载项目,但也无法添加此程序包(示例代码)...
  10. python展开 c函数中的宏预处理_C中的预处理宏