[C++11][数据结构]自己的双链表实现
这个双链表,是我模仿stl的list制作的,只实现了一些基本功能,像merge,transfer这些就没有实现,用户可以用基本操作来自己做外部实现。
我没有选用stl的[begin,end)迭代器模式,而是使用传统的[head,tail]。不过,为了配合stl算法,我还是加了两个begin(),end()方法,模拟了一下stl容器。模拟的还算及格,至少我可以做类似for (; begin != end; ++begin)这样的事,也可以让我的容器搭配一些stl算法,这在之后的demo里可以看到。不过,我的iterator很朴素,所以不能用于std::sort。
至于模拟的实现,我的方法是让所有越界的迭代器都指向一个预先设定好的内存地址。然后用户调用end()方法的时候,就返回指向这个内存地址的迭代器。这样,当我的迭代器越界的时候,就和end()指向的内存地址一样了。
代码采用C++11实现,在Win7 Mingw32 Gcc4.7的环境下,demo运行正常。如果发现写的不对的地方,还请回复一下。
以下是类的实现:
#pragma once #include <cstddef>
#include <stdexcept> namespace jt { template <class value_t>
class list {
friend class list<value_t>; private:
struct node {
value_t val;
node *next, *prev;
} *_head = nullptr,
*_tail = nullptr; size_t _siz; enum { endpointer = }; public:
class iterator {
friend class iterator;
friend class list<value_t>; public:
iterator(node *nn = nullptr) { _init(nn); }
iterator(const iterator &i) { _init(i.n); } value_t& operator*() const { return n->val; }
value_t* operator->() const { return &(operator*()); }
iterator operator++() { _inc(); return *this; }
iterator operator++(int) { iterator tmp = *this; _inc(); return tmp; }
iterator operator--() { _dec(); return *this; }
iterator operator--(int) { iterator tmp = *this; _dec(); return tmp; }
bool operator==(iterator& i) const { return i.n == n; }
bool operator!=(iterator& i) const { return i.n != n; } private:
node *n; void _init(node *nn) {
if (nn) {
n = nn;
} else {
n = (node*)endpointer;
}
} void _inc() { n = (n->next) ? n->next : (node*)endpointer; } // increment
void _dec() { n = (n->prev) ? n->prev : (node*)endpointer; } // decrement
}; list() { clear(); }
list(const list<value_t> &l) { if (&l != this) _init(l.begin(), l.end()); }
~list() { clear(); } bool empty() const { return !_head; } void clear() {
if (!empty()) {
node *tmp;
for (node *n = _head; n; n = tmp) {
tmp = n->next;
delete n;
} _head = nullptr;
_tail = nullptr;
_siz = ;
}
} void insert(const iterator &pos, const value_t &val) {
if (pos.n == _head) {
push_front(val);
} else {
node *n = new node;
n->val = val;
n->next = pos.n;
n->prev = pos.n->prev; pos.n->prev->next = pos.n->prev = n;
++_siz;
}
} void erase(const iterator &pos) {
if (pos.n == _head) {
pop_front();
} else if (pos.n == _tail) {
pop_back();
} else {
pos.n->prev->next = pos.n->next;
pos.n->next->prev = pos.n->prev;
delete pos.n;
--_siz;
}
} iterator head() const { return iterator(_head); }
iterator tail() const { return iterator(_tail); } iterator begin() const { return iterator(_head); }
iterator end() const { return iterator((node*)endpointer); } void push_front(const value_t &val) {
node *n = new node;
n->val = val;
n->next = _head;
n->prev = nullptr; if (empty()) _tail = n;
else _head->prev = n;
_head = n; ++_siz;
} void push_back(const value_t &val) {
node *n = new node;
n->val = val;
n->next = nullptr;
n->prev = _tail; if (empty()) _head = n;
else _tail->next = n;
_tail = n; ++_siz;
} void pop_front() {
if (_siz == ) {
throw std::logic_error("Empty List");
} else if (_siz == ) {
clear();
} else {
node *tmp = _head->next;
delete _head;
_head = tmp;
_head->prev = nullptr;
} --_siz;
} void pop_back() {
if (_siz == ) {
throw std::logic_error("Empty List");
} else if (_siz == ) {
clear();
} else {
node *tmp = _tail->prev;
delete _tail;
_tail = tmp;
_tail->next = nullptr;
} --_siz;
} value_t front() const { return *head(); }
value_t back() const { return *tail(); } size_t size() const { return _siz; } private:
template <class iter>
void _init(iter head, iter tail) {
clear(); // copy
if (head && tail) {
for (; head != tail; ++head) {
push_back(*head);
}
push_back(*tail);
}
}
}; }
我没有做测试,而是直接做了一个demo。
这个demo是一个正整数的统计计算器。可以插入,删除,求和,求平均数,等等。
以下是demo的代码,同样是C++11:
#include "list.h"
#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
#include <numeric>
#include <algorithm>
#include <map>
#include <functional> int main() {
jt::list<unsigned> cont;
std::string buf;
std::string helpmsg =
"h for HELP\n"
"s for SUM\n"
"a for AVERAGE\n"
"z for SIZE\n"
"i,n,p for INSERT n AT p\n"
"e,n for ERASE AT p\n"
"p,n for PUSH_BACK n\n"
"q for QUIT"; int n = -;
int p = -; // create func
std::map<char, std::function<void()>> func;
func['h'] = [&]() { std::cout << helpmsg << std::endl; };
func['s'] = [&]() { std::cout << "sum: " << std::accumulate(cont.begin(), cont.end(), ) << std::endl; };
func['a'] = [&]() { std::cout << "average: " << double(std::accumulate(cont.begin(), cont.end(), )) / cont.size() << std::endl; };
func['z'] = [&]() { std::cout << "size: " << cont.size() << std::endl; };
func['i'] = [&]() {
auto i = cont.begin();
while (--p) ++i;
cont.insert(i, n);
};
func['e'] = [&]() {
auto i = cont.begin();
while (--n) { ++i; }
cont.erase(i);
};
func['p'] = [&]() { cont.push_back(n); };
func['q'] = [](){}; char *optargs = "hsaziepq"; while (buf != "q") {
// display
std::cout << "\n[ ";
std::for_each(cont.head(), cont.end(), [&](const unsigned &n) { std::cout << n << " "; });
std::cout << "]" << std::endl; // read in args
std::cout << optargs << "> ";
std::cin >> buf; if (!strchr(optargs, buf[])) {
std::cout << "Wrong Argument" << std::endl;
} else {
sscanf(buf.c_str(), "%*c,%d,%d", &n, &p);
func[buf[]]();
}
} return ;
}
下面我使用demo的记录,看了可能会比较好理解代码一点:
[ ]
hsaziepq> h
h for HELP
s for SUM
a for AVERAGE
z for SIZE
i,n,p for INSERT n AT p
e,n for ERASE AT p
p,n for PUSH_BACK n
q for QUIT [ ]
hsaziepq> s
sum: [ ]
hsaziepq> z
size: [ ]
hsaziepq> p, [ ]
hsaziepq> p, [ ]
hsaziepq> p, [ ]
hsaziepq> a
average: [ ]
hsaziepq> s
sum: [ ]
hsaziepq> z
size: [ ]
hsaziepq> i,, [ ]
hsaziepq> e, [ ]
hsaziepq> i,, [ ]
hsaziepq> i,, [ ]
hsaziepq> i,, [ ]
hsaziepq> e, [ ]
hsaziepq> s
sum: [ ]
hsaziepq> a
average: [ ]
hsaziepq> z
size: [ ]
hsaziepq> q
[C++11][数据结构]自己的双链表实现的更多相关文章
- 数据结构图文解析之:数组、单链表、双链表介绍及C++模板实现
0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...
- C# 数据结构 - 单链表 双链表 环形链表
链表特点(单链表 双链表) 优点:插入和删除非常快.因为单链表只需要修改Next指向的节点,双链表只需要指向Next和Prev的节点就可以完成插入和删除操作. 缺点:当需要查找某一个节点的时候就需要一 ...
- 深入理解Redis 数据结构—双链表
在 Redis 数据类型中的列表list,对数据的添加和删除常用的命令有 lpush,rpush,lpop,rpop,其中 l 表示在左侧,r 表示在右侧,可以在左右两侧做添加和删除操作,说明这是一个 ...
- 数据结构(C达到)------- 双链表
双链表中的每个节点包含两个指针域,指针域包含其后继节点的内存地址,还有一个指针所存储的存储器地址其领域前驱节点. 双向链表结点的类型描写叙述: //双向链表的类型描写叙述 typedef int El ...
- 数据结构与算法之PHP实现链表类(单链表/双链表/循环链表)
链表是由一组节点组成的集合.每个节点都使用一个对象的引用指向它的后继.指向另一个节点的引用叫做链表. 链表分为单链表.双链表.循环链表. 一.单链表 插入:链表中插入一个节点的效率很高.向链表中插 ...
- Python与数据结构[0] -> 链表/LinkedList[1] -> 双链表与循环双链表的 Python 实现
双链表 / Doubly Linked List 目录 双链表 循环双链表 1 双链表 双链表和单链表的不同之处在于,双链表需要多增加一个域(C语言),即在Python中需要多增加一个属性,用于存储指 ...
- Java数据结构和算法之链表
三.链表 链结点 在链表中,每个数据项都被包含在‘点“中,一个点是某个类的对象,这个类可认叫做LINK.因为一个链表中有许多类似的链结点,所以有必要用一个不同于链表的类来表达链结点.每个LINK对象中 ...
- 数组、单链表和双链表介绍 以及 双向链表的C/C++/Java实现
概要 线性表是一种线性结构,它是具有相同类型的n(n≥0)个数据元素组成的有限序列.本章先介绍线性表的几个基本组成部分:数组.单向链表.双向链表:随后给出双向链表的C.C++和Java三种语言的实现. ...
- 新秀nginx源代码分析数据结构篇(两) 双链表ngx_queue_t
nginx源代码分析数据结构篇(两) 双链表ngx_queue_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csdn. ...
随机推荐
- NCBI database download
ascp -T -l 200M -i ~/.aspera/connect/etc/asperaweb_id_dsa.openssh --host=ftp-private.ncbi.nlm.nih.go ...
- [Think In Java]基础拾遗1 - 对象初始化、垃圾回收器、继承、组合、代理、接口、抽象类
目录 第一章 对象导论第二章 一切都是对象第三章 操作符第四章 控制执行流程第五章 初始化与清理第六章 访问权限控制第七章 复用类第九章 接口 第一章 对象导论 1. 对象的数据位于何处? 有两种方式 ...
- Mysql连表之多对多
说明 这里的文章是接着前面 Mysql连表一对多 写的. 连表多对多 可以理解成一夫多妻和一妻多夫. 男人表: nid name 1 xxx 2 yyy 3 zzz 女人表: nid name 1 a ...
- elk系列6之tcp模块的使用
preface tcp模块的使用场景如下: 有一台服务器A只需要收集一个日志,那么我们就可以不需要在这服务器上安装logstash,我们通过在其他logstash上启用tcp模块,监听某个端口,然后我 ...
- elasticsearch curl operation
Elastic Search API Index.简单的介绍了使用Elastic Search 如何建立索引. ElasticSearch-API-Index 索引创建API允许初始化一个索引.Ela ...
- Mono-D在MacOS上的设置
1. 下载DMD 建议下载tar.xz压缩包,不建议下载dmg安装包,因为dmg中没有src,而后面需要用src中的内容设置代Code Completion. 地址:http://dlang.org/ ...
- getCanonicalName和getSimpleName getName的区别与应用
接口: package com.test; public interface Fruit { } 一个实现类: package com.test; public class Apple impleme ...
- PHP代码编写规范
一. 变量命名 a) 所有字母都使用小写 b) 首字母根据变量值类型指定 i. 整数i ii. 浮点数f iii. 字符串s iv. 布尔值b v. 数组a vi. 对象o vii. 资源r viii ...
- Unix/Linux进程间通信(一):概述
序 Linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的.而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进 ...
- Android中的动画机制
1 逐帧动画 逐帧动画 就是一系列的图片按照一定的顺序展示的过程. 逐帧动画很简单, 只需要在drawable中或者anim中定义一个Animation-list 其中包含多个it ...