// 双向线性链表容器
#include <cstring>
#include <iostream>
#include <stdexcept>
using namespace std; // 链表类模板
template<typename T>
class List
{
public:
// 构造、析构、支持深拷贝的拷贝构造和拷贝赋值
List(void) : m_head(NULL), m_tail(NULL) {}
~List(void)
{
clear();
} List(List const& that) : m_head(NULL), m_tail(NULL)
{
for (Node* node = that.m_head; node != NULL;
node = node->m_next)
push_back(node->m_data);
} List& operator = (List const& rhs)
{
if (&rhs != this)
{
List list(rhs);
swap(m_head, list.m_head);
swap(m_tail, list.m_tail);
}
return *this;
} // 获取首元素
T& front(void)
{
if (empty())
throw underflow_error("链表下溢! "); //下溢异常
return m_head->m_data;
} T const& front(void) const
{
return const_cast<List*>(this)->front();
} // 向首部压入
void push_front(T const& data)
{
m_head = new Node(data, NULL, m_head);
if (m_head->m_next != NULL)
m_head->m_next->m_prev = m_head;
else
m_tail = m_head;
} // 从首部弹出
void pop_front(void)
{
if (empty())
throw underflow_error("链表下溢! ");
Node* next = m_head->m_next;
delete m_head;
m_head = next;
if (m_head)
m_head->m_prev = NULL;
else
m_tail = NULL;
} // 获取尾元素
T& back(void)
{
if (empty())
throw underflow_error("链表下溢!");
return m_tail->m_data;
} T const& back(void) const
{
return const_cast<List*>(this)->back();
} // 向尾部压入
void push_back(T const& data)
{
m_tail = new Node(data, m_tail);
if (m_tail->m_prev != NULL)
m_tail->m_prev->m_next = m_tail;
else
m_head = m_tail;
} // 从尾部弹出
void pop_back(void)
{
if (empty())
throw underflow_error("链表下溢! ");
Node* prev = m_tail->m_prev;
delete m_tail;
m_tail = prev;
if (m_tail != NULL)
m_tail->m_next = NULL;
else
m_head = NULL;
} // 删除全部匹配元素
void remove(T const& data)
{
for (Node* node = m_head, *next; node != NULL;
node = next)
{
next = node->m_next;
if (equal(data, node->m_data))
{
if (node->m_prev != NULL)
node->m_prev->m_next = node->m_next;
else
m_head = node->m_next; if (node->m_next)
node->m_next->m_prev = node->m_prev;
else
m_tail = node->m_prev; delete node;
}
}
} // 清空
void clear(void)
{
while (!empty())
pop_back();
} // 判空
bool empty(void) const
{
return NULL == m_head && NULL == m_tail;
} // 大小
size_t size(void) const
{
size_t nodes = 0;
for (Node* node = m_head; node != NULL;
node = node->m_next)
++nodes;
return nodes;
} // 下标运算符————SHIT!
T& operator[] (size_t i)
{
for (Node* node = m_head; node != NULL;
node = node->m_next)
if (0 == i--)
return node->m_data;
throw out_of_range("下标越界!");
} T const& operator[] (size_t i) const
{
return const_cast<List&>(*this)[i];
} // 插入输出流
friend ostream& operator << (ostream& os,
List const& list)
{
for (Node* node = list.m_head; node != NULL;
node = node->m_next)
os << *node;
return os;
} private:
// 节点类模板
class Node
{
public:
Node(T const& data, Node* prev = NULL, Node* next = NULL)
: m_data(data), m_prev(prev), m_next(next) {}
friend ostream& operator << (ostream& os, Node const& node)
{
return os << '[' << node.m_data << ']';
}
T m_data; // 数据
Node* m_prev; // 前指针
Node* m_next; // 后指针
}; // 推断元素是否相等
bool equal(T const & a, T const& b) const
{
return a == b;
} Node* m_head; // 头指针
Node* m_tail; // 尾指针
public:
// 正向迭代器
class Iterator
{
public:
Iterator(Node* head = NULL, Node* tail = NULL, Node* node = NULL)
: m_head(head), m_tail(tail), m_node(node) {}
bool operator == (Iterator const& rhs) const
{
return m_node == rhs.m_node;
} bool operator != (Iterator const& rhs) const
{
return ! (*this == rhs);
} Iterator& operator++ (void)
{
if (m_node)
m_node = m_node->m_next;
else
m_node = m_head;
return *this;
} Iterator const operator++ (int)
{
Iterator old = *this;
++*this;
return old;
} Iterator& operator-- (void)
{
if (m_node)
m_node = m_node->m_prev;
else
m_node = m_tail;
return *this;
} Iterator const operator-- (int)
{
Iterator old = *this;
--*this;
return old;
} T& operator* (void) const
{
return m_node->m_data;
} T* operator->(void) const
{
return &**this;
}
private:
Node* m_head;
Node* m_tail;
Node* m_node;
friend class List;
}; // 获取起始正向迭代器————指向第一个元素
Iterator begin(void)
{
return Iterator(m_head, m_tail, m_head);
} // 获取终止正向迭代器————指向最后一个元素的下一个位置
Iterator end(void)
{
return Iterator(m_head, m_tail);
} // 在正向迭代器前插入,返回指向新插入元素的迭代器
Iterator insert(Iterator loc, T const& data)
{
if (loc == end())
{
push_back(data);
return Iterator(m_head, m_tail, m_tail);
}
else
{
Node* node = new Node(data, loc.m_node->m_prev, loc.m_node);
if (node->m_prev)
node->m_prev->m_next = node;
else
m_head = node;
node->m_next->m_prev = node;
return Iterator(m_head, m_tail, node);
}
} // 删除迭代器所指向的元素。并返回该元素之后的迭代器
Iterator erase(Iterator loc)
{
if (loc == end())
throw invalid_argument("无效參数!");
if (loc.m_node->m_prev)
loc.m_node->m_prev->m_next = loc.m_node->m_next;
else
m_head = loc.m_node->m_next;
if (loc.m_node->m_next)
loc.m_node->m_next->m_prev = loc.m_node->m_prev;
else
m_tail = loc.m_node->m_prev;
Node* next = loc.m_node->m_next;
delete loc.m_node;
return Iterator(m_head, m_tail, next);
} // 常正向迭代器
// 反向迭代器
// 常反向迭代器 }; // 针对char const* 类型的成员特化版本号
template<>
bool List<char const*>::equal(char const* const& a, char const* const& b) const
{
return (0 == strcmp(a, b));
}

【C++】双向线性链表容器的实现的更多相关文章

  1. python算法:LinkedList(双向线性链表)的实现

    LinkedList是一个双向线性链表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer).由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一 ...

  2. 【二叉树->链表】二叉树结构转双向线性链表结构(先序遍历)

    二叉树存储结构属于非线性链表结构,转化成线性链表结构,能简化操作和理解.然而由非线性转线性需要对整个树遍历一次,不同的遍历方式转化结果页不一样.下面以先序为例. 方法一: 递归法.递归遍历二叉树,因为 ...

  3. 数据结构算法C语言实现(五)---2.3重新定义线性链表及其基本操作

    一.简述 ...由于链表在空间的合理利用上和插入.删除时不需要移动等的优点,因此在很多场合下,它是线性表的首选存储结构.然而,它也存在着实现某些基本操作,如求线性表的长度时不如顺序存储结构的缺点:另一 ...

  4. javascript实现数据结构:线性表--线性链表(链式存储结构)

    上一节中, 线性表的顺序存储结构的特点是逻辑关系上相邻的两个元素在物理位置上也相邻,因此可以随机存取表中任一元素,它的存储位置可用一个简单,直观的公式来表示.然后,另一方面来看,这个特点也造成这种存储 ...

  5. javascript实现数据结构与算法系列:功能完整的线性链表

    由于链表在空间的合理利用上和插入,删除时不需要移动等的有点,因此在很多场合下,它是线性表的首选存储结构.然而,它也存在着实现某些基本操作,如求线性表长度时不如顺序存储结构的缺点:另一方面,由于在链表中 ...

  6. select 函数实现 三种拓扑结构 n个客户端的异步通信 (完全图+线性链表+无环图)

    一.这里只介绍简单的三个客户端异步通信(完全图拓扑结构) //建立管道 mkfifo open顺序: cl1 读 , cl2 cl3 向 cl1写 cl2 读 , cl1 cl3 向 cl2写 cl3 ...

  7. 线性链表的双向链表——java实现

    .线性表链式存储结构:将采用一组地址的任意的存储单元存放线性表中的数据元素. 链表又可分为: 单链表:每个节点只保留一个引用,该引用指向当前节点的下一个节点,没有引用指向头结点,尾节点的next引用为 ...

  8. C++线性序列容器<vector>简单总结

    C++线性序列容器<vector>简单总结 vector是一个长度可变的数组,使用的时候无须声明上限,随着元素的增加,Vector的长度会自动增加:Vector类提供额外的方法来增加.删除 ...

  9. 用c语言创建双向环形链表

    作为一个C开发人员,无论在求职笔试题中,还是在工程项目中,都会遇到用c语言创建双向环形链表.这个也是理解和使用c指针的一项基本功. #include<...>//头文件省略 typedef ...

随机推荐

  1. 处理sql锁死问题

    --SQL Server死锁的查询方法:   exec master.dbo.p_lockinfo 0,0; ---显示死锁的进程,不显示正常的进程   exec master.dbo.p_locki ...

  2. Slow HTTP Denial of Service Attack 漏洞解决办法

    编辑 删除 问题名称: Slow HTTP Denial of Service Attack 问题URL http://10.238.*.*:58*** 风险等级: 高 问题类型: 服务器配置类 漏洞 ...

  3. MFC_2.8 使用状态栏工具栏

    使用状态栏工具栏 1.资源-添加-TOOLBAR 画图标.画了一个,第二个会出来. 2.头文件添加成员 CToolBar m_ToolBar; CStatusBar m_StatusBar; 3.初始 ...

  4. 并发编程学习笔记(10)----并发工具类CyclicBarrier、Semaphore和Exchanger类的使用和原理

    在jdk中,为并发编程提供了CyclicBarrier(栅栏),CountDownLatch(闭锁),Semaphore(信号量),Exchanger(数据交换)等工具类,我们在前面的学习中已经学习并 ...

  5. RabbitMQ系列(五)--高级特性

    在上一篇文章讲解MQ消息可靠性投递和幂等性中有提到confirm机制的重要性,现在更相信的说明一下 一.Confirm机制 Confirm就是消息确认,当Producer发送消息,如果Broker收到 ...

  6. Description Resource Path Location Type Missing artifact com.********:framework:jar:1.0.2 pom.xml /项目名 line **** Maven Dependency Problem

    问题具体描述如下图所示: 对于该问题本人是这么解决的. 在window下[Preferences]目录找到[Maven]下的[usersetting] 查看local repository 里面的路径 ...

  7. springAOP源码解析-190313

    Spring相关笔记 SpringAOP讲解 子路老师讲解 spring与aspectj的区别答:它们的区别是 spring是动态加载 aspectj是静态加载,再编译过程就已经实现切面,此时会往代码 ...

  8. php第二十八节课

    文件上传 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...

  9. linux cut-连接文件并打印到标准输出设备上

    博主推荐:获取更多 linux文件内容查看命令 收藏:linux命令大全 cut命令用来显示行中的指定部分,删除文件中指定字段.cut经常用来显示文件的内容,类似于下的type命令. 说明:该命令有两 ...

  10. linux find-在指定目录下查找文件

    推荐:更多Linux 文件查找和比较 命令关注:linux命令大全 find命令用来在指定目录下查找文件.任何位于参数之前的字符串都将被视为欲查找的目录名.如果使用该命令时,不设置任何参数,则find ...