1. 序:

本文参考了侯捷的 《STL 源码分析》一书,出于兴趣,自行实现了简单的 list 容器。

学习了 STL 的 list 容器的源代码,确实能够提高写链表代码的能力。其中的 sort 函数,可谓是非常神奇。。。

2. 实现的细节

STL 的 list 容器采用了一个带有尾节点的环状双向链表。 如下图所示:

// Last Update:2014-04-20 18:39:47
/**
* @file my_list.h
* @brief a simple list
* @author shoulinjun@126.com
* @version 0.1.00
* @date 2014-04-18
*/ #ifndef MY_LIST_H
#define MY_LIST_H #include <iostream>
#include <cstddef>
#include <cassert> /**
* list node
*/
template<class T>
struct list_node
{
typedef list_node<T>* pointer;
pointer prev;
pointer next;
T data;
}; /**
* list's iterator
* users can use it to iteratate over this list container
*/
template<class T>
struct list_iterator
{
typedef T value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef list_iterator iterator; list_iterator(list_node<T> *p = NULL) : node(p) {} reference operator*() { return node->data; }
iterator& operator++(){
node = node->next;
return *this;
}
iterator operator++(int){
iterator tmp = *this;
++*this;
return tmp;
}
iterator& operator--(){
node = node->prev;
return *this;
}
iterator operator--(int){
iterator tmp = *this;
--*this;
return tmp;
}
bool operator==(const iterator &rhs){
return node == rhs.node;
}
bool operator!=(const iterator &rhs){
return node != rhs.node; } list_node<T> *node;
}; /**
* a simple list container
*/
template<class T>
class MyList
{
public:
typedef T value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef list_iterator<T> iterator;
typedef const list_iterator<T> const_iterator;
typedef T& reference;
typedef const T& const_reference;
typedef list_node<T>* link_type; MyList();
MyList(size_type n, T value = T());
//template<class InputIterator>
//MyList(InputIterator first, InputIterator last); // copy control
MyList(const MyList&);
MyList& operator=(const MyList&);
~MyList(); bool empty() const { return node->next == node;}
difference_type size() const; iterator begin() {return iterator(node->next);}
iterator end() {return iterator(node);}
iterator begin() const {return iterator(node->next);}
iterator end() const {return iterator(node);}
iterator rbegin() {return iterator(node->prev);}
iterator rbegin() const {return iterator(node->prev);} iterator insert(iterator position, const T& x); void swap(MyList& );
void push_back(const T& x);
void pop_back() {
iterator tmp = end();
erase(--tmp);
} void push_front(const T& x);
void pop_front() {erase(begin());} void reverse();
void merge(MyList &);
void sort(); void remove(const T&x);
iterator erase(iterator position);
void clear(); void splice(iterator position, MyList& x) {
if(!x.empty()){
transfer(x.begin(), x.end());
}
} void splice(iterator position, MyList&, iterator i){
iterator j = i;
++ j;
if (position == i || position == j) return;
transfer(position, i, j);
} void splice(iterator position, MyList&, iterator first, iterator last) {
if(first != last){
transfer(position, first, last);
}
} void print();
protected:
list_node<T> *node;
static std::allocator<list_node<T> > alloc; link_type get_node(){
link_type p = alloc.allocate(1);
return p;
} void put_node(link_type p){
alloc.deallocate(p, 1);
} link_type create_node(const T& x){
link_type p = get_node();
new (&p->data) T(x);
return p;
} void destroy_node(link_type p){
(&p->data)->~T();
put_node(p);
} void empty_initialize(){
node = get_node();
node->prev = node;
node->next = node;
} void transfer(iterator position, iterator first, iterator last);
}; template<class T>
std::allocator<list_node<T> > MyList<T>::alloc; template<class T>
MyList<T>::MyList()
{
empty_initialize();
} template<class T>
MyList<T>::MyList(size_type n, T value)
{
empty_initialize();
for(size_type i(0); i!=n; ++i)
insert(begin(), value);
} template<class T>
void MyList<T>::clear()
{
link_type p = node->next;
link_type next(NULL); while(p != node){
next = p->next;
destroy_node(p);
p = next;
}
node->prev = node;
node->next = node;
} template<class T>
MyList<T>::~MyList()
{
clear();
destroy_node(node);
node = NULL;
} //copy control
template<class T>
MyList<T>::MyList(const MyList &rhs)
{
empty_initialize();
for(iterator it = rhs.begin(); it != rhs.end(); ++it)
insert(end(), *it);
} template<class T>
MyList<T>& MyList<T>::operator=(const MyList &rhs)
{
clear();
for(iterator it = rhs.begin(); it != rhs.end(); ++it)
insert(end(), *it);
return *this;
} template<class T>
typename MyList<T>::difference_type MyList<T>::size() const
{
difference_type len(0);
link_type p = node->next;
for(; p != node; p = p->next, ++len);
return len;
} template<class T>
typename MyList<T>::iterator MyList<T>::insert(iterator position, const T& x)
{
link_type new_node = create_node(x); new_node->next = position.node;
new_node->prev = position.node->prev;
position.node->prev->next = new_node;
position.node->prev = new_node; return iterator(new_node);
} template<class T>
inline void MyList<T>::push_back(const T& x)
{
insert(end(), x);
} template<class T>
inline void MyList<T>::push_front(const T& x)
{
insert(begin(), x);
} template<class T>
typename MyList<T>::iterator MyList<T>::erase(iterator position)
{
link_type next_node = link_type(position.node->next);
link_type prev_node = link_type(position.node->prev); prev_node->next = next_node;
next_node->prev = prev_node;
destroy_node(position.node); return iterator(next_node);
} // remove all nodes equal to x
template<class T>
void MyList<T>::remove(const T& x)
{
link_type prev_node(node);
link_type cur(node->next);
link_type next_node(NULL); while(cur != node)
{
if(cur->data == x){
/* delete node */
next_node = cur->next;
prev_node->next = next_node;
next_node->prev = prev_node; destroy_node(cur);
cur = next_node;
}
else{
prev_node = cur;
cur = cur->next;
}
}
} /**
* move [first, last) ahead of position
* an auxillary function
*/
template<class T>
void MyList<T>::transfer(iterator position, iterator first, iterator last)
{
if(position != last)
{
link_type first_node = first.node;
link_type rear_node = last.node->prev; //separate [first, last) from their list
first_node->prev->next = last.node;
last.node->prev = first_node->prev; //add [first, last)
first_node->prev = position.node->prev;
rear_node->next = position.node;
position.node->prev->next = first_node;
position.node->prev = rear_node;
}
} template<class T>
void MyList<T>::swap(MyList &rhs)
{
if(this->node != rhs.node){
link_type tmp = node;
node = rhs.node;
rhs.node = tmp;
}
} template<class T>
void MyList<T>::reverse()
{
/* length == 0 || length == 1*/
if(node->next == node || node->next->next == node)
return;
iterator first = begin(), old(NULL);
++ first;
while(first != end()){
old = first;
++ first;
transfer(begin(), old, first);
}
} template<class T>
void MyList<T>::merge(MyList &x)
{
iterator first1 = this->begin();
iterator last1 = this->end();
iterator first2 = x.begin();
iterator last2 = x.end(); // *this and x are sorted incrementally
while(first1 != last1 && first2 != last2)
{
if(*first2 < *first1) {
iterator next = first2;
transfer(first1, first2, ++next);
first2 = next;
}
else
++first1;
}
if(first2 != last2) {
transfer(end(), first2, last2);
}
assert(x.empty());
} template<class T>
void MyList<T>::print()
{
iterator cur = begin();
while(cur != end())
{
std::cout << *cur << " ";
++ cur;
}
std::cout << std::endl;
} /**
* interesting sort function for list
* std::sort is not fit for list
* which requires random iterator
*/
template<class T>
void MyList<T>::sort()
{
/* length == 0 || length == 1*/
if(node->next == node || node->next->next == node)
return; MyList<T> carry;
MyList<T> counter[64];
int fill = 0;
while(!empty())
{
/* carry get the first node */
carry.splice(carry.begin(), *this, begin()); int i = 0;
while(i < fill && !counter[i].empty())
{
counter[i].merge(carry);
carry.swap(counter[i++]);
}
carry.swap(counter[i]);
if(i == fill) ++fill;
} for(int i=1; i<fill; ++i)
counter[i].merge(counter[i-1]);
swap(counter[fill-1]);
} #endif /*MY_LIST_H*/

动手实现自己的 STL 容器《2》---- list的更多相关文章

  1. 动手实现自己的 STL 容器 《1》---- vector

    本文参考了侯捷的 <STL 源码分析>一书,出于兴趣,自行实现了简单的 vector 容器. 之后会陆续上传 list, deque 等容器的代码,若有错误,欢迎留言指出. vector ...

  2. STL容器

    啦啦啦,今天听啦高年级学长讲的STL容器啦,发现有好多东西还是有必要记载的,毕竟学长是身经百战的,他在参加各种比赛的时候积累的经验可不是一天两天就能学来的,那个可是炒鸡有价值的啊,啊啊啊啊啊 #inc ...

  3. c++ stl容器set成员函数介绍及set集合插入,遍历等用法举例

    c++ stl集合set介绍 c++ stl集合(Set)是一种包含已排序对象的关联容器.set/multiset会根据待定的排序准则,自动将元素排序.两者不同在于前者不允许元素重复,而后者允许. 1 ...

  4. STL容器删除元素的陷阱

    今天看Scott Meyers大师的stl的用法,看到了我前段时间犯的一个错误,发现我写的代码和他提到错误代码几乎一模一样,有关stl容器删除元素的问题,错误的代码如下:std::vector< ...

  5. 【转】c++中Vector等STL容器的自定义排序

    如果要自己定义STL容器的元素类最好满足STL容器对元素的要求    必须要求:     1.Copy构造函数     2.赋值=操作符     3.能够销毁对象的析构函数    另外:     1. ...

  6. GDB打印STL容器内容

    GDB调试不能打印stl容器内容,下载此文件,将之保存为~/.gdbinit就可以使用打印命令了. 打印list用plist命令,打印vector用pvector,依此类推. (gdb) pvecto ...

  7. STL容器迭代器失效分析

    连续内存序列容器(vector, string, deque) 对于连续内存序列STL容器,例如vector,string,deque,删除当前iterator会使得后面所有的iterator都失效, ...

  8. STL容器的适用情况

     转自http://hsw625728.blog.163.com/blog/static/3957072820091116114655254/ ly; mso-default-props:yes; m ...

  9. STL容器的遍历删除

    STL容器的遍历删除 今天在对截包程序的HashTable中加入计时机制时,碰到这个问题.对hash_map中的每个项加入时间后,用查询函数遍历hash_map,以删除掉那些在表存留时间比某个阈值长的 ...

随机推荐

  1. js页面刷新之实现框架内外刷新(整体、局部)

    这次总结的是框架刷新: 框架内外的按钮均可以定义网页重定向, 框架内部页面的按钮可以实现局部刷新, 框架外部页面的按钮可以实现整页刷新. 代码如下(两个html页面): <!--主界面index ...

  2. 指定页面配置https(apache/tomcat)

    apache/tomcat服务器下配置https         apache下配置https:             首先在网站根目录下,找到.htaccess文件(如果没有则新建),apache ...

  3. (原创) cocos2dx使用Curl连接网络(客户端)

    0. 环境: winxpsp3, vs2010, cocos2dx@2.1.4 1. 新建一个Helloworld工程 2. HelloworldScene.h里面重写virtual bool ccT ...

  4. 【Unity3D游戏开发】之利用语法糖添加自定义拓展方法(下) (十八)

    首先需要声明的是“语法糖”这个词绝非贬义词,它可以给我带来方便,是一种便捷的写法,编译器会帮我们做转换:而且可以提高开发编码的效率,在性能上也不会带来损失.这让java开发人员羡慕不已,呵呵. 1.  ...

  5. 《BI那点儿事》数据仓库建模:星型模式、雪片模式

    数据仓库建模 — 星型模式Example of Star Schema 数据仓库建模 — 雪片模式Example of Snowflake Schema 节省存储空间 一定程度上的范式 星形 vs.雪 ...

  6. python 发送邮件实例

    留言板回复作者邮件提醒 -----------2016-5-11 15:03:58-- source:python发送邮件实例

  7. mysql 登录及常用命令

    一.mysql服务的启动和停止 mysql> net stop mysql mysql> net start mysql 二.登陆mysql mysql> 语法如下: mysql - ...

  8. Java:描述反射机制的作用?举几个反射的应用?

    比较全的解释了:JAVA反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方 ...

  9. Php数据类型之整型详解

    php中支持的数据类型 在php中主要支持8种数据类型.和3中伪类型的一个形式.8种数据类型分为以下三3大类,第一个就是我们的标量类型,标量类型它只能存储单一数据,那第二大类就是我们的复合类型,第三个 ...

  10. ToolStrip添加自定义的DateTimePicker

    直接新建一个类,代码如下: [ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.All), DefaultEven ...