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

双向循环链表 实现的功能
头部插入结点建立链表 尾部插入结点建立链表
实现指定位置插入结点 查找给定数值是否存在
删除指定位置的结点 修改指定位置的结点
双向链表的长度 打印双向链表

定义双向链表的结点

双向循环链表的结点由三部分构成,用于指向当前节点的直接前驱节点的指针域,用于存储数据元素的数据域 ,以及用于指向当前节点的直接后继节点的指针域。

在之前的C++语言实现双向链表时已经给大家解释了封装的结点的特点,不需要作太大的改变,我们需要封装一个结点类,定义了结点的三个要素,并利用构造函数实现初始化,另外,考虑到在双向循环链表中要用到结点类,所以将双向链表类定义为结点的友元类。

template<class T>
class doubleCircularLinkedList;//声明一下双向循环链表,以免定义友元时报错
template <class T>
class doubleCircularLinkedListNode
{private:doubleCircularLinkedListNode<T> *prior;//双向结点前驱指针指向该结点的前驱结点T data;//储存结点数据doubleCircularLinkedListNode<T> *next;//双向结点的后驱指针指向该结点的后继结点//将双向循环链表类定义为结点的友元类friend  class doubleCircularLinkedList<T>;public://结点的无参构造函数,将结点指针域初始化为NULLdoubleCircularLinkedListNode(){prior = NULL;next = NULL;}//结点的有参构造函数,初始化指针域和数据域doubleCircularLinkedListNode(T _data,doubleCircularLinkedListNode<T> *_prior = NULL,doubleCircularLinkedListNode<T> *_next = NULL){prior = _prior;//初始化前驱指针data = _data;//初始化数据域next = _next;//初始化后继指针}~doubleCircularLinkedListNode(){prior = NULL;next = NULL;}
};

双向链表的基本操作

本次实现的操作跟双向链表实现的操作基本一样,实现了双向循环链表头部插入结点, 尾部插入结点,指定位置插入结点建立链表, 查找给定数值的指定位置,删除指定位置的结点,修改指定位置的结点,双向循环链表的长度,打印双向循环链表,接下来逐一进行讲解实现:

头部插入结点建立链表

实现双向循环链表的头部插入结点,之前的双向链表因为在头部和尾部的指针都是指向NULL的,所以需要分情况来处理,然而双向循环链表没有元素时这两个指针都是指向自身的,因此并不需要分情况处理,都需要修改四个指针。
因此,头部插入结点实现如下:

template<class T>
bool doubleCircularLinkedList<T>::insertNodeByhead(T item)
{//创建一个新的结点doubleCircularLinkedListNode<T>* newNode = new doubleCircularLinkedListNode<T>(item);if (newNode == NULL){cout << "内存分配失败,新结点无法创建" << endl;return false;}else{newNode->prior = headNode;newNode->next = headNode->next;headNode->next->prior=newNode;headNode->next = newNode;return true;}
}

尾部插入结点建立链表

在尾部插入结点,当然第一步需要找到最后一个结点,然后在其后进行插入,调整四个指针即可。

template<class T>
bool doubleCircularLinkedList<T>::insertNodeBytail(T item)
{//创建一个新的结点doubleCircularLinkedListNode<T>* newNode = new doubleCircularLinkedListNode<T>(item);if (newNode == NULL){cout << "内存分配失败,新结点无法创建" << endl;return false;}//首先找到最后一个结点doubleCircularLinkedListNode<T>* lastNode = headNode;while(lastNode->next != headNode){lastNode = lastNode->next;//没找到就一直循环}//找到之后调整四个指针headNode->prior = newNode;newNode->next = headNode;lastNode->next = newNode;newNode->prior = lastNode;return true;
}

实现指定位置插入结点

在指定位置插入只需要两步走,首先也是找到指定的位置,然后就是插入新结点的指针的调整,中间插入是最复杂的,都需要调整四个指针,最后让新结点与前继结点建立关系,实现新结点的插入。

template<class T>
bool doubleCircularLinkedList<T>::insertNode(T item,int n)
{if(n<1){cout<<"输入的非有效位置!"<<endl;return false;}doubleCircularLinkedListNode<T>* pMove = headNode;//创建一个新的指针,设置为游标指针//首先找到插入位置for(int i=1;i<n;i++){pMove = pMove->next;if(pMove == NULL&& i<=n){cout<<"插入位置无效!"<<endl;return false;}}//创建一个新的结点doubleCircularLinkedListNode<T>* newNode = new doubleCircularLinkedListNode<T>(item);if (newNode == NULL){cout << "内存分配失败,新结点无法创建" << endl;return false;}//插入新的结点newNode->next = pMove->next;   if (pMove->next != headNode){pMove->next->prior = newNode;}newNode->prior = pMove;pMove->next = newNode;return true;
}

查找给定数值是否存在

查找给定元素,也就是一个遍历双向循环链表的过程,从头结点的下一个结点开始遍历,毕竟第一个头结点是没有储存数据项的。

template<class T>
bool doubleCircularLinkedList<T>::findData(T item)
{doubleCircularLinkedListNode<T> *pMove = headNode->next; //设置游标指针doubleCircularLinkedListNode<T> *pMoveprior = headNode;//指定结点前一个结点的指针//找到指定位置while(pMove->data != item){pMoveprior = pMove;pMove = pMoveprior->next;//如果没有找到特殊处理if(pMove == headNode){return false;}}return true;
}

删除指定位置的结点

删除指定的结点,第一步查找到删除的结点,需要定义一个删除指针临时指向将要删除的结点,最后指针处理删除之后别忘了释放该结点空间。

template<class T>
bool doubleCircularLinkedList<T>::deleteData(int n)
{if (n<1||n>getLength()){cout << "输入非有效位置" << endl;return false;}doubleCircularLinkedListNode<T> * pMove = headNode;//设置游标指针doubleCircularLinkedListNode<T> * pDelete;             //查找删除结点的位置for (int i = 1; i <= n; i++){pMove = pMove->next;                                         //游标指针后移}//删除结点pDelete = pMove;      pMove->prior->next = pDelete->next;pMove->next->prior = pDelete->prior;delete pDelete;//释放空间return true;
}

修改指定位置的结点

修改指定位置的结点数据,当然还是得找到指定位置,然后对其进行修改,修改之后将原来的数据以引用的形式返回。

template<class T>
bool doubleCircularLinkedList<T>::changeListElements(int n,T item,T &x)
{if (n<1||n>getLength()){cout << "输入非有效位置" << endl;return false;}doubleCircularLinkedListNode<T> *pMove = headNode->next;  //设置游标指针for(int i=1;i<n;i++)//找到指定位置1{pMove = pMove->next;}x = pMove->data;pMove->data = item;return true;
}

双向循环链表的长度

计算双向链表的长度的函数,在双向链表的私有成员封装了一个变量length,以此来记录双向链表的长度,遍历双向链表,逐一进行计算结点数就是双向链表的长度。

template<class T>
int doubleCircularLinkedList<T>::getLength()
{doubleCircularLinkedListNode<T> *pMove = headNode->next;  //设置游标指针int length=0;//遍历链表,计算结点数while(pMove != headNode){pMove = pMove->next;  //游标指针后移length++;       //计算length}return length;
}

打印双向循环链表

template<class T>
void doubleCircularLinkedList<T>::printLinkedlist()
{//从第二个结点开始打印,表头不含数据doubleCircularLinkedListNode<T>* pMove = headNode->next;while(pMove !=headNode)//如果pMove->next != headNode这样写,最后一个结点是不会打印的{cout<<pMove->data<<" ";pMove = pMove->next;//移动指针}cout<<endl;
}

以上就是我简要的给大家分享的C++实现双向循环链表,因为实现了双向链表,所以基本上实现思路差不多,唯一的不同就是在循环一词不同,这一不同就是头结点的前驱指针和尾结点的后驱指针指向不同,要是还是不太清楚的可以去那篇博客看看。本次的完整代码已经全部上传到github! (C++实现双向循环链表),还想了解其他的数据结构实现的可以去我的博客,我们一起讨论啊,一起进步!

C++实现双向循环链表相关推荐

  1. 数据结构与算法(2-2)线性表之链式存储(单链表、静态链表、循环链表、双向循环链表)

    目录 一.单链表 1.存储方式 2.插入 3.删除 总代码: 二.静态链表 1.存储方式 2.插入 3.删除 4.遍历 总代码: 三.循环链表 总代码: 四.双向循环链表 1.存储方式: 2.插入和删 ...

  2. 链表 -- 双向循环链表(线性表)

    1,双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱.所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点.一般我们都构造双向循环 ...

  3. C++实现有哨兵的双向循环链表

    C++实现有哨兵的双向循环链表: #include<iostream> #include<stack> using namespace std; template<cla ...

  4. 数据结构 -- 双向循环链表

    这篇文章写的是双向循环链表,这也是个非常经典的数据结构,我们在看 Linux 内核代码时就经常会遇到它.比如,在Linux的内核中实现进程描述符,使用的就是双向循环链表,因为它使用起来很方便,每个节点 ...

  5. 用动态数组模拟双向循环链表

    简单来说其实使用数组模拟LinkedList.同LinkedList的操作基本相似.  基本原理为:数组存放Entry对象,包含数据部分,指针部分(数组下标)  添加,删除基本操作改变指针.数组包含两 ...

  6. java与数据结构(4)---java实现双向循环链表

    线性表之链式存储结构双向循环链表 双向循环链表:每个结点包含了数据.直接前驱地址指针和直接后驱地址指针,头结点的直接前驱指向尾结点,尾结点的直接后驱指向头结点,头尾相连构成一个可正可反的圆环.可以形象 ...

  7. 数据结构-单向循环链表、双向循环链表、仿真链表

    一.单向循环链表: 1.概念: 单向循环链表是单链表的另一种形式,其结构特点是链表中最后一个结点的指针不再是结束标记,而是指向整个链表的第一个结点,从而使单链表形成一个环. 和单链表相比,循环单链表的 ...

  8. Python创建一个循环链表、双向循环链表

    循环链表与双向循环链表 循环链表 循环链表相较于单链表,将末尾结点的连接域指向了头结点,就类似于将播放器的顺序播放改成了列表循环 双向循环链表 双向链表相较于之前的链表多了上一节点连接域,在双向链表中 ...

  9. c++17(20)-双向循环链表(不依赖具体数据)

    双向循环链表(不依赖具体数据),借鉴LINUX内核的链表结构 #include <iostream> using namespace std; struct stdlist{stdlist ...

  10. step3 . day3 数据结构之线性表 单项循环链表和双向循环链表

    1. 使用单项循环链表解决约瑟夫问题: #include <stdio.h> #include <stdlib.h> typedef struct looplist{ int ...

最新文章

  1. 深度学习-语义分割总结
  2. mysql5.5.20安装图解_mysql5.5.20的安装步骤
  3. 成功解决PackagesNotFoundError: The following packages are not available from current channels: tensorflo
  4. 思科发布全新Catalyst 2960-L系列交换机
  5. 爬虫如何监听插件_Go 爬虫之 colly 从入门到不放弃指南
  6. 前端学习(2534)vue源码解析
  7. PLSQL Developer简单使用教程
  8. leetcode [26] 删除排序数组中的重复项 / Remove Duplicates from Sorted Array
  9. Atitit 持久化 Persistence概念的艺术 目录 1. 持久化是将程序数据在持久状态和瞬时状态间转换的机制。 1 2. DBC就是一种持久化机制。文件IO也是一种持久化机制。 2 3.
  10. 肌电数据归一化并显示灰度图片
  11. 在Windows使用mingw32编译opencv
  12. 08cms房产门户系统v8.4升级补丁支持新版APP和小程序
  13. 计算机硬盘根目录是什么,解决方案:硬盘根目录是什么意思?它存储在哪里?...
  14. 7-1 最大子列和问题 (20分)(两种解法,包含联机算法)
  15. 一级域名和二级域名的区别
  16. 生动实践现代农业-国稻种芯-泸州江阳:谋定产村深度融合
  17. 算法竞赛进阶指南0x10练习6:防线
  18. 锐龙R3-3300X和i5-9400f哪个好?
  19. H7-TOOL的APP固件升级至V2.05,上位机升级至V2.05,支持CAN助手,新增华芯微特SWM和杰发科技AC78X脱机烧录(2021-05-16)
  20. 为Word文档加水印使其更加美观(转)

热门文章

  1. 计算机硬盘的常用分区工具,磁盘分区工具,详细教您硬盘分区工具diskgenius怎么使用...
  2. Java实现pdf打印文件
  3. Matlab绘制圆饼统计图pie的用法详解
  4. 用canvas画圆饼图
  5. 【数学建模】数据包络分析法
  6. 艾宾浩斯遗忘曲线-计划表30天
  7. 计算机二级vb基础教程,2017计算机二级考试内容VB
  8. [Java] 自己写了个随机抽签器
  9. 【MicroPython ESP32】ssd1306 0.96“OLED+气象数据中文显示
  10. Hightopo 2D 入门