数据结构-02-链表数据结构之双链表和循环链表
2017-11-07 18:59
369 查看
上篇博客分析了单链表:数据结构-01-链表数据结构之单链表,这篇博客将分析链表的其他几种常见形式
本文中的所有代码均在github上的项目中:List_DataStructure
双链表是最常用的一种链表形式,实际应用中双链表一般会被创建成环状形式,即头尾结点分别存储对方的地址,链表形成了一个封闭的环。
根据双链表在创建时调用空参构造函数,创建了一个结点对象,即链表的头结点,头结点的上一结点的地址pprior 和下一节点的地址pnext 存储均存储头结点地址
1.初始化一个结点类的对象pnode
2.创建一个结点类型指针pmove,用于遍历找到插入点位置
3.循环找到插入点位置,若pmove == head说明指定的插入点位置超过了链表长度
4.执行插入
如下图所示,pnode为x,即待插入节点
pmove指向节点ai
步骤一:将ai+1的地址(即ai->pnext也是pmove->pnext)赋值给pnode的下一结点地址pnext
步骤二:将ai的地址(即pmove)赋值给pnode的上一结点地址pprior
步骤三:将pnode的地址赋值给ai(即pmove)的下一结点地址pnext
步骤四:将pnode的地址赋值给ai+1(即ai+1->pprior也是pnode->pnext->pprior)的上一结点地址pprior
删除链表的结点必须要两个指向待删除结点的指针配合
1.创建两个结点类型指针pmove,和pdel,pmove用于遍历找到待删除结点
2.循环找到插入点位置,若pmove == head说明指定的待删除结点位置超过了链表长度
3.执行删除
如下图所示,pmove指向节点ai,即待删除节点
步骤一:通过赋值使pdel指向节点ai
步骤二:将ai+1的地址赋给ai-1的下一结点地址pnext(即ai-1->pnext也是pmove->pprior->pnext)
步骤三:将ai-1的地址赋给ai+1的上一结点地址pprior(即ai+1->pprior也是pmove->pnext->pprior)
本文中的所有代码均在github上的项目中:List_DataStructure
双链表
双链表也叫双向链表,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。双链表是最常用的一种链表形式,实际应用中双链表一般会被创建成环状形式,即头尾结点分别存储对方的地址,链表形成了一个封闭的环。
1.双链表的基本结构:
双链表的开始是一个头指针,每个结点中都有指向下一结点及上一结点的地址双链表的C++实现:
1.双链表的结点类
template<typename Type> class DoubleLinkedList; template<typename Type> class DoubleLinkedListNode { private: friend typename DoubleLinkedList<Type>; //构造函数和析构函数 DoubleLinkedListNode() :pprior(nullptr), pnext(nullptr) {} DoubleLinkedListNode(const Type item, DoubleLinkedListNode<Type> * next = nullptr, DoubleLinkedListNode<Type> * prior = nullptr) :data(item), pnext(next), pprior(prior) {} ~DoubleLinkedListNode() { pprior = nullptr; pnext = nullptr; } public: //单链表节点对象的基本方法 Type GetData(); private: Type data; DoubleLinkedListNode * pprior; DoubleLinkedListNode * pnext; };
2.双链表类
template <typename Type> class DoubleLinkedList { public: DoubleLinkedList() :head(new DoubleLinkedListNode<Type>()) { head->pprior = head; head->pnext = head; } ~DoubleLinkedList() { MakeEmpty(); delete head; } //对双链表的基本操 void MakeEmpty(); void Insert(Type item, int i = 0); void Remove(int i = 0); void RemoveAll(Type item); //返回双聊表的基本信息 int length(); Type Get(int i); //查找和排序 DoubleLinkedListNode<Type> * SequentialSearch(Type item); //基础功能 void Print(); private: //链表的头节点是私有的 SingleLinkedListNode<Type> *head; };
2.双链表的初始化:
双链表的空参构造函数:DoubleLinkedList() :head(new DoubleLinkedListNode<Type>()) { head->pprior = head; head->pnext = head; }
根据双链表在创建时调用空参构造函数,创建了一个结点对象,即链表的头结点,头结点的上一结点的地址pprior 和下一节点的地址pnext 存储均存储头结点地址
3.向双链表中插入数据:
向双向循环链表中插入数据时应注意链表是封闭环状,所以使用循环或递归时要注意结束条件//向双链表中插入元素 template <typename Type> void DoubleLinkedList<Type>::Insert(Type item, int i = 0) { if (i < 0){ cout << "请输入一个大于0的数" << endl; } DoubleLinkedListNode<Type> *pmove = head; DoubleLinkedListNode<Type> *pnode = new DoubleLinkedListNode<Type>(item); for (int j = 0; j < i; j++){ pmove = pmove->pnext; if (pmove == head) { cout << "i值越界,链表没有那么长!" << endl; //结束程序 exit(1); } } pnode->pnext = pmove->pnext; pnode->pnext = pmove; pmove->pnext = pnode; pnode->pnext->pprior = pnode; }
1.初始化一个结点类的对象pnode
2.创建一个结点类型指针pmove,用于遍历找到插入点位置
3.循环找到插入点位置,若pmove == head说明指定的插入点位置超过了链表长度
4.执行插入
pnode->pnext = pmove->pnext; //步骤一 pnode->pprior= pmove; //步骤二 pmove->pnext = pnode; //步骤三 pnode->pnext->pprior = pnode; //步骤四
如下图所示,pnode为x,即待插入节点
pmove指向节点ai
步骤一:将ai+1的地址(即ai->pnext也是pmove->pnext)赋值给pnode的下一结点地址pnext
步骤二:将ai的地址(即pmove)赋值给pnode的上一结点地址pprior
步骤三:将pnode的地址赋值给ai(即pmove)的下一结点地址pnext
步骤四:将pnode的地址赋值给ai+1(即ai+1->pprior也是pnode->pnext->pprior)的上一结点地址pprior
4.删除双链表中的数据:
//删除双链表中的元素 template <typename Type> void DoubleLinkedList<Type>::Remove(int i = 0) { if (i < 0) { cout << "请输入一个大于0的数" << endl; } DoubleLinkedListNode<Type> *pmove = head, *pdel; for (int j = 0; j < i; j++) { pmove = pmove->pnext; //当pmove == head,说明pmove移动了一个链表长度,又绕回了链表起始点 if (pmove == head) { cout << "i值越界,链表没有那么长!" << endl; //结束程序 exit(1); } } pdel = pmove; pmove->pprior->pnext = pdel->pnext; pmove->pnext->pprior = pdel->pprior; Type temp = pdel->data; cout << "删除的结点中保存的数据是:" << temp << endl; delete pdel; }
删除链表的结点必须要两个指向待删除结点的指针配合
1.创建两个结点类型指针pmove,和pdel,pmove用于遍历找到待删除结点
2.循环找到插入点位置,若pmove == head说明指定的待删除结点位置超过了链表长度
3.执行删除
pdel = pmove; //步骤一 pmove->pprior->pnext = pdel->pnext; //步骤二 pmove->pnext->pprior = pdel->pprior; //步骤三
如下图所示,pmove指向节点ai,即待删除节点
步骤一:通过赋值使pdel指向节点ai
步骤二:将ai+1的地址赋给ai-1的下一结点地址pnext(即ai-1->pnext也是pmove->pprior->pnext)
步骤三:将ai-1的地址赋给ai+1的上一结点地址pprior(即ai+1->pprior也是pmove->pnext->pprior)
相关文章推荐
- 数据结构【线性表(二)链表】项目之循环双链表应用
- 数据结构链表之循环双链表
- 2015年大二上-数据结构-链表(6)-循环双链表应用
- 数据结构学习心得——双链表和循环链表
- Python写数据结构:单向循环链表
- 2-8-双循环链表链式存储结构-线性表-第2章-《数据结构》课本源码-严蔚敏吴伟民版
- 数据结构--循环链表--尾指针
- 数据结构Java实现04----循环链表、仿真链表
- 数据结构系列之链表——双链表插入
- 数据结构学习之循环链表结构
- 数据结构-循环链表
- C++数据结构--单向循环链表(实现头插法,尾插法)
- 数据结构习题分析:已知由一个线性链表表示的线性表中含有三类字符的数据元素,是编写算法将该线性表分割为三个循环链表,其中每个。。。。。
- 数据结构之循环链表
- 数据结构Java实现04----循环链表、仿真链表
- 数据结构-有头双向循环链表2(封装)
- 数据结构_线性表_链式存储_单向循环链表的基本操作
- 小猪的数据结构辅助教程——2.7 线性表中的双向循环链表
- 数据结构Java实现 ----循环链表、仿真链表
- 数据结构--循环链表