list不同于vector。每一个节点的结构须要自行定义,迭代器属于双向迭代器(不是随即迭代器),也须要自行定义。和通用迭代器一样,list的迭代器须要实现的操作有:++、--、*、->、==、!=。节点的数据结构命名为list_node,迭代器的数据结构命名为list_iterator。list中对迭代器的操作不应该使用算数运算,如+2、-3这种操作,仅仅应该使用++、--来移动迭代器。STI版本号的STL使用了一个环形list,list.end()指向一个空白节点(不存放数据)作为尾节点,空白节点的next指针指向第一个节点,空白节点的prev指针指向最后一个节点,这样就能方便的实现begin()和end()操作,当list为空时,空白节点的next和prev均指向自己。这种设计是非常巧妙的,省去了非常多插入、删除操作时须要考虑的边界条件。

#ifndef __MYLIST_H__
#define __MYLIST_H__ // list节点
template <class Type>
class list_node {
public:
list_node<Type> *prev;
list_node<Type> *next;
Type data;
}; // list迭代器
template <class Type>
class list_iterator {
public:
// 迭代器必须定义的五个对应类型
typedef Type value_type;
typedef Type* pointer;
typedef Type& reference;
typedef size_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category; list_iterator() : node(NULL)
{} list_iterator(list_node<Type> *x) : node(x)
{} list_iterator(const list_iterator<Type> &x) : node(x.node)
{} // 成员函数尽量加const
bool operator== (const list_iterator<Type> &rhs) const
{
return node == rhs.node;
} bool operator!= (const list_iterator<Type> &rhs) const
{
return !(operator==(rhs)); // 调用现有函数。好的策略
} // 对迭代器接引用返回指向数据的引用
reference operator* () const
{
return node->data;
} pointer operator-> () const
{
return &(operator*()); // 调用现有函数。好的策略
} list_iterator& operator++ ()
{
node = node->next;
return *this;
} list_iterator operator++ (int)
{
list_iterator<Type> old = *this;
++(*this);
return old;
} list_iterator& operator-- ()
{
node = node->prev;
return *this;
} list_iterator operator-- (int)
{
list_iterator<Type> old = *this;
--(*this);
return old;
} // 迭代器通过这个指针与某个节点相联系
list_node<Type> *node;
}; // list数据结构,SGI中的list是一个环形链表。这里同样
// list内部使用list_node訪问每个保存数据的节点。对外则返回给用户一个list_iterator迭代器,这是须要注意的
template <class Type>
class List {
public:
typedef list_iterator<Type> iterator; // iterator类型是每个容器必备的,应该尽早定义它
typedef size_t size_type; // 构造函数
List()
{
node = get_node();
// 前后指针都指向自己。表示此list为空
node->next = node;
node->prev = node;
} iterator begin()
{
return (list_iterator<Type>)node->next;
} iterator end()
{
return (list_iterator<Type>)node;
} bool empty()
{
return node->next == node; // 參见默认构造函数
} size_type size()
{
size_type len = 0;
distance(begin(), end(), len);
return len;
} Type& front()
{
return *begin();
} Type& back()
{
return *(--end());
} // 插入操作
iterator insert(iterator position, const Type &value)
{
list_node<Type> *newNode = create_node(value);
newNode->next = position.node;
newNode->prev = position.node->prev;
position.node->prev->next = newNode;
position.node->prev = newNode;
return (iterator)newNode; // 显示类型转换
} void push_back(const Type &value)
{
insert(end(), value);
} void push_front(const Type &value)
{
insert(begin(), value);
} // 删除操作
iterator erase(iterator position)
{
list_node<Type> *next = position.node->next;
list_node<Type> *prev = position.node->prev;
prev->next = next;
next->prev = prev;
destroy_node(position.node);
return (iterator)next;
} void pop_back()
{
iterator tmp = end();
erase(--tmp);
} void pop_front()
{
erase(begin());
} // 清除全部节点
void clear()
{
list_node<Type> *pnode = node->next;
while (pnode != node)
{
list_node<Type> *tmp = pnode->next;
destroy_node(pnode);
pnode = tmp;
}
node->next = node;
node->prev = node;
} // 删除值为value的全部节点
void remove(const Type &value)
{
// 为了使用上面的erase,这里定义iterator而不是list_node
iterator first = begin();
iterator last = end(); while (first != last)
{
iterator next = first;
++next;
if (*first == value)
erase(first);
first = next;
}
} private:
// 分配一个节点
list_node<Type>* get_node()
{
return alloc.allocate(1);
} // 释放一个节点
void put_node(list_node<Type> *p)
{
alloc.deallocate(p, 1);
} // 分配并构造一个节点
list_node<Type>* create_node(const Type &value)
{
list_node<Type> *p = get_node();
alloc.construct(&(p->data), value);
return p;
} // 析构并释放一个节点
void destroy_node(list_node<Type> *p)
{
alloc.destroy(&(p->data));
put_node(p);
} private:
list_node<Type> *node; // 空白节点,指向list.end()
static std::allocator< list_node<Type> > alloc; // 空间配置器
}; // 类中的静态成员一定要记得在类外定义,否则链接时会出错
template <class Type>
std::allocator< list_node<Type> > List<Type>::alloc; #endif

析构函数忘记写了,这里补上:

	~List()
{
clear();
if (node != NULL)
delete node;
}

測试代码:

int main()
{
List<int> l; l.push_back(1);
l.push_back(2);
l.push_back(3);
l.push_back(4);
l.push_back(5);
copy(l.begin(), l.end(), ostream_iterator<int>(cout, " "));
cout << endl;
// 1 2 3 4 5 List<int>::iterator iter = find(l.begin(), l.end(), 3);
iter = l.erase(iter);
copy(l.begin(), l.end(), ostream_iterator<int>(cout, " "));
cout << endl;
// 1 2 4 5 l.insert(iter, 123);
copy(l.begin(), l.end(), ostream_iterator<int>(cout, " "));
cout << endl;
// 1 2 123 4 5 l.push_front(0);
copy(l.begin(), l.end(), ostream_iterator<int>(cout, " "));
cout << endl;
// 0 1 2 123 4 5 l.pop_back();
copy(l.begin(), l.end(), ostream_iterator<int>(cout, " "));
cout << endl;
// 0 1 2 123 4 l.pop_front();
copy(l.begin(), l.end(), ostream_iterator<int>(cout, " "));
cout << endl;
// 1 2 123 4 l.clear();
copy(l.begin(), l.end(), ostream_iterator<int>(cout, " "));
cout << endl;
// null l.push_back(1);
l.push_back(2);
l.push_back(3);
l.push_front(4);
l.push_front(5);
l.push_front(6); l.remove(1);
l.remove(2);
l.remove(3);
l.remove(5); copy(l.begin(), l.end(), ostream_iterator<int>(cout, " "));
cout << endl;
system("pause");
return 0;
}

执行结果:

參考:

《STL源代码剖析》

C++简易list的更多相关文章

  1. .NET里简易实现AOP

    .NET里简易实现AOP 前言 在MVC的过滤器章节中对于过滤器的使用就是AOP的一个实现了吧,时常在工作学习中遇到AOP对于它的运用可以说是很熟练了,就是没想过如果自己来实现的话是怎么实现的,性子比 ...

  2. 在.Net中实现自己的简易AOP

    RealProxy基本代理类 RealProxy类提供代理的基本功能.这个类中有一个GetTransparentProxy方法,此方法返回当前代理实例的透明代理.这是我们AOP实现的主要依赖. 新建一 ...

  3. .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”

    FileProvider构建了一个抽象文件系统,作为它的两个具体实现,PhysicalFileProvider和EmbeddedFileProvider则分别为我们构建了一个物理文件系统和程序集内嵌文 ...

  4. 自己来实现一个简易的OCR

    来做个简易的字符识别 ,既然是简易的 那么我们就不能用任何的第三方库 .啥谷歌的 tesseract-ocr, opencv 之类的 那些玩意是叼 至少图像处理 机器视觉这类课题对我这种高中没毕业的人 ...

  5. php+websocket搭建简易聊天室实践

    1.前言 公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室.于是搜集各种资料看文档.找实例自己也写了个简单的聊天室. http连接分为短 ...

  6. 用Go实现的简易TCP通信框架

    接触到GO之后,GO的网络支持非常令人喜欢.GO实现了在语法层面上可以保持同步语义,但是却又没有牺牲太多性能,底层一样使用了IO路径复用,比如在LINUX下用了EPOLL,在WINDOWS下用了IOC ...

  7. .NET里简易实现IoC

    .NET里简易实现IoC 前言 在前面的篇幅中对依赖倒置原则和IoC框架的使用只是做了个简单的介绍,并没有很详细的去演示,可能有的朋友还是区分不了依赖倒置.依赖注入.控制反转这几个名词,或许知道的也只 ...

  8. MVC 验证码实现( 简易版)

    现在网站上越来越多的验证码,使用场景也是越来越多,登陆.注册.上传.下载...等等地方,都有可能大量使用到验证码,那么制作验证码到底有多简单呢?我们一起来看下最简易版的验证码实现过程- 验证码的基本步 ...

  9. 基于 getter 和 setter 撸一个简易的MVVM

    Angular 和 Vue 在对Angular的学习中,了解到AngularJS 的两个主要缺点: 对于每一次界面时间,Ajax 或者 timeout,都会进行一个脏检查,而每一次脏检查又会在内部循环 ...

  10. nginx简易教程

    概述 什么是nginx? Nginx (engine x) 是一款轻量级的Web 服务器 .反向代理服务器及电子邮件(IMAP/POP3)代理服务器. 什么是反向代理? 反向代理(Reverse Pr ...

随机推荐

  1. webapp通用选择器:iosselect

    1,这个组件解决什么问题 在IOS系统中,safari浏览器的select标签默认展示样式和iOS-UIPickerView展示方式一致,形如下图: 这个选择器操作方便,样式优美.但是在安卓系统中展示 ...

  2. 从零开始搭建Vue组件库——VV-UI

    前言: 前端组件化是当今热议的话题之一,也是我们在开发单页应用经常会碰到的一个问题,现在我们有了功能非常完善的Element-UI.各个大厂也相继宣布开源XXX-UI.但是也会存在一些问题,比如每个公 ...

  3. 【Kafka源码】broker被选为controller之后的连锁反应

    [TOC] 今天我们主要分析下broker被选为controller之后,主要干了什么.门面代码先列出来: def onControllerFailover() { if (isRunning) { ...

  4. 如何在工程中使用axis2部署webservice

    有一个最简单的方法就是把axis2.war中的内容作为Web Project的基础, 来进行开发. 不过为了更清楚的了解如何在一个已有的Web Project中嵌入axis2, 那就手动来配置.大致分 ...

  5. Cordic算法——圆周系统之向量模式

    旋转模式用来解决三角函数,实现极坐标到直角坐标的转换,基础理论请参考Cordic算法--圆周系统之旋转模式.那么,向量模式则用来解决反三角函数的问题,体现的应用主要是直角坐标向极坐标转换,即已知一点的 ...

  6. C# WPF动点任意移动气泡画法(解决方案使用到数学勾股定理、正弦定理、向量知识)。

    许久没写博客了,最近在研究WPF下气泡的画法,研发过程还是比较艰辛的(主要是复习了高中的数学知识,MMP全忘光了),这篇博客主要是提供一个思路给大家参考,如果有大神还有更好的解决方案可以不吝您的言论尽 ...

  7. Python数据分析(二): Pandas技巧 (2)

    Pandas的第一部分: http://www.cnblogs.com/cgzl/p/7681974.html github地址: https://github.com/solenovex/My-Ma ...

  8. 面试相关-转载-well,yzl——持续更新

    转载yl,yzl大神的面经,顺便自己复习一下专业课的内容 操作系统相关: 什么是进程, 什么是线程.它们之间的区别和联系. 进程管理内存资源+运行过程, 线程只管理运行过程, 线程要在进程提供的资源基 ...

  9. jQuery操作input改变value属性值

    今天写了一个表单元素,在用户点击的时候会清空input中的内容,当鼠标点击其他地方的时候会把输入的值保存为input的value值 类似于这样的效果 当用户点击的时候文字消失. html代码 < ...

  10. 安装vue-cli时出现的错误,cmd 卡住

    今天在构建vue 时遇到个问题, cmd 执行 vue init webpack my-project 时 , 出现如下乱码, 然后 页面 卡住在 项目说明 ,操作不了, 最后发现是 nodejs 版 ...