【C++】双向线性链表容器的实现
// 双向线性链表容器
#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++】双向线性链表容器的实现的更多相关文章
- python算法:LinkedList(双向线性链表)的实现
LinkedList是一个双向线性链表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer).由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一 ...
- 【二叉树->链表】二叉树结构转双向线性链表结构(先序遍历)
二叉树存储结构属于非线性链表结构,转化成线性链表结构,能简化操作和理解.然而由非线性转线性需要对整个树遍历一次,不同的遍历方式转化结果页不一样.下面以先序为例. 方法一: 递归法.递归遍历二叉树,因为 ...
- 数据结构算法C语言实现(五)---2.3重新定义线性链表及其基本操作
一.简述 ...由于链表在空间的合理利用上和插入.删除时不需要移动等的优点,因此在很多场合下,它是线性表的首选存储结构.然而,它也存在着实现某些基本操作,如求线性表的长度时不如顺序存储结构的缺点:另一 ...
- javascript实现数据结构:线性表--线性链表(链式存储结构)
上一节中, 线性表的顺序存储结构的特点是逻辑关系上相邻的两个元素在物理位置上也相邻,因此可以随机存取表中任一元素,它的存储位置可用一个简单,直观的公式来表示.然后,另一方面来看,这个特点也造成这种存储 ...
- javascript实现数据结构与算法系列:功能完整的线性链表
由于链表在空间的合理利用上和插入,删除时不需要移动等的有点,因此在很多场合下,它是线性表的首选存储结构.然而,它也存在着实现某些基本操作,如求线性表长度时不如顺序存储结构的缺点:另一方面,由于在链表中 ...
- select 函数实现 三种拓扑结构 n个客户端的异步通信 (完全图+线性链表+无环图)
一.这里只介绍简单的三个客户端异步通信(完全图拓扑结构) //建立管道 mkfifo open顺序: cl1 读 , cl2 cl3 向 cl1写 cl2 读 , cl1 cl3 向 cl2写 cl3 ...
- 线性链表的双向链表——java实现
.线性表链式存储结构:将采用一组地址的任意的存储单元存放线性表中的数据元素. 链表又可分为: 单链表:每个节点只保留一个引用,该引用指向当前节点的下一个节点,没有引用指向头结点,尾节点的next引用为 ...
- C++线性序列容器<vector>简单总结
C++线性序列容器<vector>简单总结 vector是一个长度可变的数组,使用的时候无须声明上限,随着元素的增加,Vector的长度会自动增加:Vector类提供额外的方法来增加.删除 ...
- 用c语言创建双向环形链表
作为一个C开发人员,无论在求职笔试题中,还是在工程项目中,都会遇到用c语言创建双向环形链表.这个也是理解和使用c指针的一项基本功. #include<...>//头文件省略 typedef ...
随机推荐
- POJ_1847_Tram
Tram Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 11159 Accepted: 4089 Description ...
- Tomcat 使用redis实现session共享
准备工作: 1.安装nginx 环境搭建参考:https://blog.csdn.net/fd2025/article/details/79878326 nginx.conf的编辑: 2.同一台机器配 ...
- Java基础——面向对象(封装——继承——多态 )
对象 对象: 是类的实例(实现世界中 真 实存在的一切事物 可以称为对象) 类: 类是对象的抽象描述 步骤: 1.定义一个类 (用于 描述人:) ( * 人:有特征和行为) 2.根据类 创建对象 -- ...
- Bat 脚本(常用命令)
Bat 批处理脚本 (常用) Bat 批处理脚本 === Content === 1. Rem 和 :: Rem 为注释命令,能回显. :: 为符号注释,不能回显. %行内注释内容% ===== (不 ...
- tarjan求强连通分量模板
什么是强连通分量? 百度百科 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(stro ...
- TestNG忽略测试
用@Test(enabled = false) 声明需要被忽略执行的测试方法 package com.janson; import org.testng.annotations.Test; publi ...
- (二)Python脚本开头两行的:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用
#!usr/bin/env python # -*- coding: utf-8 -*- def test(): print('hello, world') if __name__ == " ...
- highcharts图表的常见操作
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- exists关键词和case表达式
首先声明一下,exist和case没有必然联系,这里只是为了一起整理个笔记. EXIST谓词 如果存在对应的记录,返回TRUE.否则,返回FALSE.*实际使用中,即使不适用exist,基本也可以使用 ...
- FJoi2017 1月20日模拟赛 恐狼后卫(口糊动规)
Problem 1 恐狼后卫(wolf.cpp/c/pas) [题目描述] 著名卡牌游戏<石炉传说>中有一张随从牌:恐狼后卫.恐狼后卫的能力是使得相邻随从的攻击力提高. 现在有n张恐狼后卫 ...