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. Iptables防火墙

    1 位置 使用vim /usr/sysconfig/iptables 2 启动.关闭.保存 service iptables stop service iptables start service i ...

  2. JS闭包导致循环给按钮添加事件时总是执行最后一个

    加入如下脚本代码: <script> var list_obj = document.getElementsByTagName('li'); for (var i = 0; i <= ...

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

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

  4. [问题2015S12] 复旦高等代数 II(14级)每周一题(第十三教学周)

    [问题2015S12]  设 \(A\) 为 \(n\) 阶实矩阵, 若对任意的非零 \(n\) 维实列向量 \(\alpha\), 总有 \(\alpha'A\alpha>0\), 则称 \( ...

  5. linux 如何开机自动运行sh脚本

    vi /etc/rc.d/rc.local #自动启动oracleecho 502 >/proc/sys/vm/hugetlb_shm_group su - oracle -c 'sh /dat ...

  6. 备用帖子1Shell(Shell R语言)

    shell========================== echo 1 > /proc/sys/vm/drop_caches 清理内存 free -m du -h --max-depth= ...

  7. http知识

    http请求的过程:客户端发起请求,创建端口:http服务器在端口监听客户端请求:http服务器向客户端返回状态和内容. 浏览器搜索自身的DNS缓存-->搜索操作系统自身的DNS缓存(浏览器没有 ...

  8. hdu4511小明系列故事——女友的考验(ac自动机+最短路)

    链接 预处理出来任意两点的距离,然后可以顺着trie树中的节点走,不能走到不合法的地方,另开一维表示走到了哪里,依次来更新. 注意判断一下起点是不是合法. #include <iostream& ...

  9. Server asks us to fall back to SIMPLE auth, but this client is configured to only allow secure connections.

    我是在flume向hdfs 写(sink)数据时遇到的这个错误. Server (是指hdfs) asks us to fall back to SIMPLE auth, but this clien ...

  10. 无法获取有关Windows NT 组\用户‘组\用户’的信息,错误代码0x5(Microsoft SQL Server,错误:15404)

    配置了复制,在删除某个发布的时候,突然报此错误,无法删除此发布:   使用语句修改:  ALTER AUTHORIZATION ON DATABASE:: [数据库名] TO [sa] 即修改数据库的 ...