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. zigbee学习之路(三):按键的控制

    一.前言 通过前一次的实验,相信大家都已经对cc2530程序的编写有了一定的认识,这次我们来操作和实验的是cc2530上的按键模块. 二.原理分析 我们先来看一下按键的原理图: 根据原理图我们可以得出 ...

  2. jenkins对结果进行断言问题

    TextFinder plugin插件 Jenkins在判定使用shell scripts完成build成功与否的时候,是根据shell最终的返回值是否为零来判定的:零即成功,非零即失败.这点判定事实 ...

  3. 关于 Oracle 的数据导入导出及 Sql Loader (sqlldr) 的用法

    在 Oracle 数据库中,我们通常在不同数据库的表间记录进行复制或迁移时会用以下几种方法: 1. A 表的记录导出为一条条分号隔开的 insert 语句,然后执行插入到 B 表中2. 建立数据库间的 ...

  4. Cheatsheet: 2015 11.01 ~ 11.30

    Golang Roadomatic: Node vs. Go Quick Guide to Golang for Java Developers 3 Go Gotchas Web Choosing a ...

  5. .NET IL学习笔记(一)

    参考资料: 1. <.NET IL Assembler> 2. NGEN代码产生器 3. NGEN的使用 4. IL编辑器下载 5. IL编辑器的使用 知识点: ● Common Lang ...

  6. immutableJS一些API

    原生js转换为immutableData Immutable.fromJS([1,2]) // immutable的 list Immutable.fromJS({a: 1}) // immutabl ...

  7. 《点石成金:访客至上的Web和可用性设计秘笈(原书第3版)》--- 读书笔记

    这是一本绝妙的书, 它的英语书名是“Don't make me think”.更确切的说是个小册子, 但是作者的语言实在是让人忍俊不禁. 真TM的有趣, 为毛外国人就能写出如此美妙的书? 而国人却不能 ...

  8. 从零开始HTML(一 2016/9/19)

    就是准备跟着W3C上的教程过一遍HTML啦,边看边记录更便于理解记忆吧~ 1.属性 HTML 标签可以拥有属性.属性提供了有关 HTML 元素的更多的信息.属性总是以名称/值对的形式出现,比如:nam ...

  9. Reverse a singly linked list

    Reverse a singly linked list. /** * Definition for singly-linked list. * struct ListNode { * int val ...

  10. (原创)详解Quartus导出网表文件:.qxp和.vqm

    当项目过程中,不想给甲方源码时,该如何?我们可以用网表文件qxp或者vqm对资源进行保护. 下面讲解这两个文件的具体生成步骤: 一.基本概念 QuartusII的qxp文件为QuartusII Exp ...