双向链表的操作特点:

(1) “查询” 和单链表相同;

(2)“插入” 和“删除”时需要同时修改两个方向上的指针。

但是对于双向循环链表则在表尾插入非常的迅速, 只需O(1)的时间,因为有指向前面的指针, 因此双向循环链表会很容易的找到位于表尾的元素,因此双向循环链表比较适用于频繁在表尾插入的情况.

空链表:

双向循环链表节点构造:

class DoubleListNode
{
private:Type data;DoubleListNode *prev;   //前向指针域DoubleListNode *next;   //后项指针域
};

因为需要将其用于DoubleList类,因此需要将其改造如下:

template <typename Type>
class DoubleListNode
{//友元声明friend class DoubleList<Type>;friend class ListIterator<Type>;template <typename T>friend ostream &operator<<(ostream &os, const DoubleList<T> &list);
private:DoubleListNode(const Type &dataValue):data(dataValue),prev(NULL),next(NULL) {}Type data;DoubleListNode *prev;   //前向指针域DoubleListNode *next;   //后项指针域
};

双向循环链表构造:

template <typename Type>
class DoubleList
{friend class ListIterator<Type>;template <typename T>friend ostream &operator<<(ostream &os, const DoubleList<T> &list);
public:DoubleList();~DoubleList();void push_back(const Type &data);void push_front(const Type &data);void insert(int position, const Type &data);void pop_front();void pop_back();void remove(const Type &removeData);bool search(const Type &searchData) const;bool isEmpty() const{return (first->next == first);}private://将节点x插入到节点previous后面void insertPrivate(DoubleListNode<Type> *previous,DoubleListNode<Type> *x);void removePrivate(DoubleListNode<Type> *x);private:DoubleListNode<Type> *first;
};

链表的构造与析构:

//构造链表
template <typename Type>
DoubleList<Type>::DoubleList()
{first = new DoubleListNode<Type>(0);first->next = first;first->prev = first;
}
//析构链表
template <typename Type>
DoubleList<Type>::~DoubleList()
{DoubleListNode<Type> *deleteNode = NULL;//保存链表尾元素DoubleListNode<Type> *tmp = first;//first首先指向第一个真实的元素first = first->next;//一路到达链表结尾while (first != tmp){deleteNode = first;first = first -> next;delete deleteNode;}// 释放掉链表的空节点(表头)delete tmp;
}

链表元素插入与删除的两大主力:

//同为private成员
//插入节点
template <typename Type>
void DoubleList<Type>::insertPrivate(DoubleListNode<Type> *previous,DoubleListNode<Type> *x)
{x->prev = previous;x->next = previous->next;previous->next->prev = x;previous->next = x;
}
//删除节点
template <typename Type>
void DoubleList<Type>::removePrivate(DoubleListNode<Type> *x){if (x == first)throw std::range_error("permission denied to delete first pointer");x->prev->next = x->next;x->next->prev = x->prev;delete x;
}

提供给客户的插入:

//插入到表尾
template <typename Type>
void DoubleList<Type>::push_back(const Type &data)
{DoubleListNode<Type> *newNode = new DoubleListNode<Type>(data);//找到first的前一个节点DoubleListNode<Type> *previous = first->prev;//插入insertPrivate(previous, newNode);
}
//插入到表头
template <typename Type>
void DoubleList<Type>::push_front(const Type &data)
{DoubleListNode<Type> *newNode = new DoubleListNode<Type>(data);//插入到first之后insertPrivate(first, newNode);
}//插入到任意位置(依position指定)
template <typename Type>
void DoubleList<Type>::insert(int position, const Type &data)
{if (position == 1)return push_front(data);int count = 1;//previous 代表着要插入位置之前的一个位置DoubleListNode<Type> *previous = first->next;//如果position过大, 则previous查找到first就会停止//此时应该将该元素插入到链表结尾while (count < position-1 && previous != first){++ count;previous = previous->next;}//如果查找到了链表结尾或此时链表为空, 因此插入到表尾if (previous == first)return push_back(data);//如果找到了合适的插入位置DoubleListNode<Type> *newNode = new DoubleListNode<Type>(data);insertPrivate(previous, newNode);
}

提供给客户的删除:

//删除表尾元素
template <typename Type>
void DoubleList<Type>::pop_back()
{removePrivate(first->prev);
}
//删除表头元素
template <typename Type>
void DoubleList<Type>::pop_front()
{removePrivate(first->next);
}//删除元素值为removeData的所有元素
template <typename Type>
void DoubleList<Type>::remove(const Type &removeData)
{if (isEmpty())throw std::range_error("link list is empty");for( DoubleListNode<Type> *searchNode = first->next;searchNode != first;searchNode = searchNode->next){if (searchNode->data == removeData)removePrivate(searchNode);}
}

查看是否存在于链表中:

template <typename Type>
bool DoubleList<Type>::search(const Type &searchData) const
{DoubleListNode<Type> *searchNode = first->next;while (searchNode != first){if (searchNode->data == searchData)return true;searchNode = searchNode->next;}return false;
}

输出链表所有元素(测试用):

template <typename Type>
ostream &operator<<(ostream &os, const DoubleList<Type> &list)
{for (DoubleListNode<Type> *currentNode = (list.first)->next;currentNode != list.first;currentNode = currentNode->next)os << currentNode->data << ' ';return os;
}

双向循环链表迭代器的设计与实现:

//除了添加了operator--, 几乎没做任何改变
template <typename Type>
class ListIterator
{
public:ListIterator(const DoubleList<Type> &_list):list(_list),currentNode((_list.first)->next) {}//重载 *operatorconst Type &operator*() const throw (std::out_of_range);Type &operator*() throw (std::out_of_range);//重载 ->operatorconst DoubleListNode<Type> *operator->() const throw (std::out_of_range);DoubleListNode<Type> *operator->() throw (std::out_of_range);//重载 ++operatorListIterator &operator++() throw (std::out_of_range);//注意:此处返回的是值,而不是referenceListIterator operator++(int) throw (std::out_of_range);//重载 --operator,// 其实这个版本的--operator是不完美的,// 因为他没有做任何的判错控制ListIterator &operator--();//注意:此处返回的是值,而不是referenceListIterator operator--(int);bool isEmpty() const{return (currentNode == list.first);}private:const DoubleList<Type> &list;DoubleListNode<Type> *currentNode;
};
template <typename Type>
const Type &ListIterator<Type>::operator*() const
throw (std::out_of_range)
{if (isEmpty())throw std::out_of_range("iterator is out of range");// 返回当前指针指向的内容return currentNode->data;
}
template <typename Type>
Type &ListIterator<Type>::operator*()
throw (std::out_of_range)
{returnconst_cast<Type &>(static_cast<const ListIterator<Type> &>(*this).operator*());
}
template <typename Type>
const DoubleListNode<Type> *ListIterator<Type>::operator->() const
throw (std::out_of_range)
{if (isEmpty())throw std::out_of_range("iterator is out of range");//直接返回指针return currentNode;
}template <typename Type>
DoubleListNode<Type> *ListIterator<Type>::operator->()
throw (std::out_of_range)
{returnconst_cast<DoubleListNode<Type> *> (static_cast<const ListIterator<Type> >(*this).operator->());
}
template <typename Type>
ListIterator<Type> &ListIterator<Type>::operator++()
throw (std::out_of_range)
{if (isEmpty())throw std::out_of_range("iterator is out of range");//指针前移currentNode = currentNode->next;return *this;
}
template <typename Type>
ListIterator<Type> ListIterator<Type>::operator++(int)
throw (std::out_of_range)
{ListIterator tmp(*this);++ (*this); //调用前向++版本return tmp;
}
template <typename Type>
ListIterator<Type> &ListIterator<Type>::operator--()
{//指针前移currentNode = currentNode->prev;return *this;
}
template <typename Type>
ListIterator<Type> ListIterator<Type>::operator--(int)
{ListIterator<Type> tmp(*this);-- (*this);return tmp;
}

测试代码:

int main()
{cout << "-------- 1 --------" << endl;DoubleList<int> myList;for (int i = 0; i < 3; ++i)myList.push_back(i+1);for (int i = 0; i < 5; ++i)myList.push_front(10+i);for (int i = 0; i < 3; ++i)myList.push_back(i+1);ListIterator<int> iter(myList), iter2(myList);while (!iter.isEmpty()){cout << *iter << ' ';++ iter;++ iter2;}cout << endl;-- iter2;while (!iter2.isEmpty()){cout << *iter2 << ' ';iter2 --;}cout << endl;cout << "-------- 2 --------" << endl;cout << myList << endl;cout << "Test insert..." << endl;myList.insert(1, 14);myList.insert(2, 13);myList.insert(2, 13);myList.insert(88, 88);cout << myList << endl;myList.pop_back();myList.pop_front();cout << myList << endl;for (int i = 0; i < 5; ++i){if (myList.search(i))cout << i << ": Have found!" << endl;elsecout << i << ": Not in the list!" << endl;}cout << "Test remove..." << endl;cout << myList << endl;int value;while (cin >> value){try{myList.remove(value);}catch (const std::exception &e){cerr << e.what() << endl;}cout << myList << endl;if (myList.isEmpty()){cout << "empty" << endl;}else{cout << "not empty" << endl;}}return 0;
}

数据结构基础(12) --双向循环链表的设计与实现相关推荐

  1. 初阶数据结构之带头+双向+循环链表增删查实现(三)

    文章目录 @[TOC](文章目录) 前言 一.带头双向循环链表的初始化 1.1带头双向循环链表的结构体定义 1.2初始化代码的实现 二.带头+双向+循环链表的增功能实现 2.1头插代码的实现 2.2尾 ...

  2. 【数据结构】带头双向循环链表的增删查改(C语言实现)

    文章目录 前言 一.什么是带头双向循环链表 二.带头双向循环链表的实现 1.结构的定义 2.链表的初始化 3.开辟新节点 4.在头部插入数据 5.在尾部插入数据 6.查找数据 7.在pos位置之前插入 ...

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

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

  4. 【数据结构】带头双向循环链表

    各位读者们好久不见了,咋们接着上一期链表来,今天来实现一下链表最难的结构,同时也是实现起来最简单的结构--带头双向循环链表.话不多说,进入主题 文章目录 前言 实现带头双向循环链表 DList.h头文 ...

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

    #include <iostream>using namespace std;int main() {typedef int ListType;typedef struct ListNod ...

  6. 数据结构——带头结点双向循环链表

    相比较与单链表,双向循环链表每个结点多了一个prev指针域,用于指向该结点的前驱,并且链表的头尾结点也用指针域相连.所以对于带头结点的双向循环链表的判空条件为head->next=head;除此 ...

  7. 数据结构基础(8) --单链表的设计与实现(1)之基本操作

    链表简介 数组的缺点: 1.元素插入:除了在数组的末尾插入元素之外,在数组的其他任何位置插入元素都需要进行数组元素的频繁移动(插入位置之后的元素都需往后移动), 时间复杂度约为O(N); 2.数组的删 ...

  8. 数据结构基础(9) --单链表的设计与实现(2)之高级操作

    链表的链接: 将第二条链表的所有内容链接到第一条链表之后, 其完整实现代码与解析如下: //链表的链接 template <typename Type> void MyList<Ty ...

  9. 数据结构基础(7) --循环队列的设计与实现

    队列 队列简称队, 也是一种操作受限的线性表, 只允许在表的一端进行插入, 而在表的另一端进行删除.其特点为"先进先出(FIFO)",故又称为先进先出的线性表,简单队列如图所示: ...

最新文章

  1. 美国《时代》周刊公布年度25大最佳发明名单
  2. kendoui仪表盘和柱状图 示例
  3. shell匹配IP和shell正则匹配捕获引用
  4. python 获取方法名_python 动态获取当前运行的类名和函数名的方法
  5. 代码生成工具CodeSmith中SchemaExplorer类API文档[转]
  6. 成功解决C4996: ‘fopen‘: This function or variable may be unsafe. Consider using fopen_s instead
  7. C/C++之学习笔记
  8. vSpere虚拟网卡介绍
  9. Api demo源码学习(4)--App/Activity/Dialog --Activity以Dialog形式呈现
  10. linux c++ 函数效率,Linux C++程序进行性能分析工具gprof使用入门
  11. mybatis多参数传递(其中包括数组)
  12. 电脑文件同步备份软件哪个好用?
  13. 计算机考试操作步骤,全国计算机等级考试网报操作流程
  14. Google在线深度学习神器Colab--实操学习
  15. 单细胞测序系列之一:测序技术的发展
  16. opencv 将白色变透明
  17. CentOS 7 部署RabbitMQ 服务
  18. Android Studio 更换个性化主题
  19. 网格顶点法向量从世界坐标到切空间坐标转换:法向贴图高低模烘焙
  20. Linux mmap 详解

热门文章

  1. 软件测试要经过哪几个阶段?
  2. 判断给定数字n是否为素数(质数)
  3. C/C++获取指定网口的IP地址
  4. 系统提升架构能力之10种mysql主从实践总结
  5. 八、栈的操作、栈空间
  6. html中,怎么样才能获得iframe页面里的内容
  7. 取出重复记录的第一条
  8. 让WEB FORM更像WINDOWS FORM: 控制窗体事件
  9. 详解数据科学与数理统计的基本概念
  10. 从入门到头秃,2018年机器学习图书TOP10