相较于 vector 的连续线性空间,List 就显得复杂很多,它的好处是每次插入或删除一个元素,就配置或释放一个元素空间。因此 list 对于空间的运用有绝对的精准。对于任何位置的元素插入或移除,永远是常数时间
- list 的节点(node)
list 本身和 list 的节点是不同的结构,需要分开设计
以下是 STL list 的节点(node)结构
//是一个双向链表
template<class T>
struct _list_node
{
typedef void* void_pointer;
void_pointer prev;
void_pointer next;
T data;
};
- list的迭代器
要点:
list 不能像 vector 一样以普通指针作为迭代器,因为其节点不保证在存储空间中连续存在
因为 STL list 是一个双向链表(double linked-list),所以 list 提供的是 `Bidirectional Iterators`
list有个重要性质:插入操作(insert)和接合操作(splice)都不会造成原有的 list 迭代器失效 (vector 中则不成立)
//对于& * 的各种运用的理解不是很透彻
//还有?????处的
#include "_list_node.cpp"
#include <iterator>
using namespace std;
template<class T, class Ref, class Ptr>
struct _list_iterator
{
typedef _list_iterator<T, T&, T*> iterator;
typedef _list_iterator<T, Ref, Ptr> self;
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef _list_node<T>* link_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
link_type node; //迭代器内部当然要有一个普通指针,指向list的节点
//constructor
_list_iterator(link_type x) : node(x) {}
_list_iterator() {}
_list_iterator (const iterator& x) : node(x.node) {} //??????????/
bool operator == (const self& x) const {return node == x.node;}
bool operator != (const self& x) const {return node != x,node;}
//以下对迭代器取值(dereference), 取的是节点的数据值
reference operator*() const {return (*node).data;}
//以下是迭代器的成员存取(member access) 运算子的标准做法
pointer operator->() const {return &(operator*());}
//对迭代器累加1,就是前进一个节点
self& operator++() //前置
{
node=(link_type) ((*node).next);
return *this;
}
self operator++(int) //后置
{
self tmp = *this;
++*this;
return tmp;
}
//对迭代器递减1,就是后退一个节点
self& operator--() //前置
{
node=(link_type) ((*node).prev);
return *this;
}
self operator--(int) //后置
{
self tmp = *this;
--*this;
return tmp;
}
};
- list的数据结构
要点:
SGI list 不仅是一个双向链表,而且还是一个环状双向链表,所以它只需要一个指针,便可以完整表现整个链表
template <class T, class Alloc = alloc> //缺省使用alloc为配置器
class list
{
protected:
typedef _list_node<T> list_node;
public:
typedef list_node* link_type;
protected:
link_type node; //只要一个指针,便可表示整个环状双向链表
//不知道要用protected or public or private
iterator begin() {return (link_type((*node).next);}
iterator end() {return node;}
bool empty() const {return node->next == node;}
size_type size() const
{
size_type result = 0;
distance(begin(),end(),result); //全局函数,第三章
return result
}
//取头节点的内容(元素值)
reference front() {return *begin();}
//取尾节点的内容(元素值)
reference back() {return *(--end());}
};
- list 的构造和内存管理
//list的构造与内存管理 constructor, push_back, insert
protected:
typedef _list_node<T> list_node;
//专属空间配置器,每次配置一个节点大小
typedef simple_alloc<list_node, Alloc> list_node_allocator;
//list_node_allocator(n) 表示配置N个节点空间
//以下四个函数,分别用来配置、释放、构造、销毁一个节点
protected:
//配置一个节点并传回
link_type get_node() {return list_node_allocator::allocate(); }
//释放一个结点
void put_node(link_type p) {list_node_allocator::deallocate(p); }
//产生(配置并构造)一个节点,带有元素值
link_type create_node (const T& x)
{
link_type p = get_node();
construct (&p->data, x); //全局函数,构造|析构 基本工具
return p;
}
//销毁(析构并释放) 一个节点
void destroy_node (link_type p)
{
destroy (&p->data); //全局函数,构造|析构 基本工具
put_node(p);
}
//default constructor 允许我们不指定任何参数做出一个空的 list 出来
public:
list() {empty_initialize(); } //产生一个空链表
protected:
void empty_initialize()
{
node = get_node(); //配置一个节点空间,令node指向它
node -> next = node; //令node头尾都指向自己,不设元素值
node -> prev = node;
}
//用 push_back() 将新元素插入list尾端时,函数内部调用insert();
// insert() 是个重载函数,其中最简单的一种如下
// 新节点将位于哨兵迭代器(标示出插入点)所指节点的前方
iterator insert (iterator position, const T& x)
{
link_type tmp = create_node(x); //产生一个节点(设内容为X)
//调整双向指针,使tmp插入进去
tmp->next = position.node;
tmp->prev = position.node -> prev;
(link_type(position.node -> prev))->next = tmp;
position.node -> prev = tmp;
return tmp;
}
- list的元素操作:
- push_front, push_back, erase, pop_front, pop_back, clear, remove, unique, splice, merge, reverse, sort
// list的元素操作:
// push_front, push_back, erase, pop_front, pop_back, clear, remove, unique, splice, merge, reverse, sort
//-----------------------------------------------------------------------
//插入一个节点,作为头节点
void push_front (const T& x) {insert(begin(), x); }
//插入一个节点,作为尾节点
void push_back (const T& x) {insert(end(), x); }
//移除迭代器 position 所指节点
iterator erase(iterator position)
{
link_type next_node = link_type(position.node->next);
link_type prve_node = link_type(position.node->prev);
prev_node->next = next_node;
next_prev->prev = prev_node;
destroy_node(postion.node);
return iterator(next_node);
}
//移除头节点
void pop_front() { erase(begin()); }
//移除尾节点
void pop_back() {iterator tmp = end(); erase(--tmp); }
//清除所有节点(整个链表)
template< class T, class Alloc>
void list<T,Alloc> :: clear()
{
link_type cur = (link_type) node->next; // begin() //???为什么node正好指的是头节点 -----》因为在创建一个新的list的时候,先创建一个空的链表,其中有定义node
while ( cur != node) //遍历每一个节点
{
link_type tmp = cur;
cur = (link_type) cur->next;
destroy_node(tmp); //销毁(析构并释放)一个节点
}
//恢复node原始状态 //产生一个空链表及 头尾都指向自己
node->next = node;
node->prev = node;
}
//将数值为 value 的所有元素移除
template<class T, class Alloc>
void list<T, Alloc>::remove(const T& value)
{
iterator first = begin();
iterator last = end();
while (first != last) //遍历每一个节点
{
iterator next = first;
++next;
if(*first == value) erase(first); //找到就移除
first = next;
}
}
//移除数值相同的连续元素, 注意,只有“连续而相同的元素”,才会被移除一个
template<class T, class Alloc>
void list<T, Alloc>::unique()
{
iterator first = begin();
iterator last = end();
if (first == last ) return; //空链表,什么都不做
iterator next = first;
while(++next != last) //遍历每一个节点
{
if(*first == *next) //如果在此区段中有相同的元素
erase(next);
else
first = next; //指针调整
next = first; //修正区段范围
}
}
// list内部提供一个所谓的迁移操作(transfer):将某连续范围的元素迁移到某个特定位置之前,为(splice,sort,merge)等奠定良好的基础
// 将 [first, last) 内的所有元素移动到postion之前
// 先连 next, 再连 prev
void transfer (iterator position, iterator first, iterator last)
{
if(position != last)
{
// 1
(*(link_type((*last.node).prev))).next = position.node;
// 2
(*(link_type((*first.node).prev))).next = last.node;
// 3
(*(link_type((*position.node).prev))).next = first.node;
// 4
link_type tmp = link_type((*position.node).prev);
// 5
(*position.node).prev = (*last.node).prev;
// 6
(*last.node).prev - (*first.node).prev;
// 7
(*first.node).prev = tmp;
}
}
//上述的 transfer 并非公开接口,List 公开接口提供的是所谓的接合操作(splice)
//为了提供各种接口弹性, list<T>::splice 有许多版本
public:
//将 x 接合于 position 所指位置之前, x 必须不同于 *this
void splice(iterator position , list& x)
{
if( !x.empty())
transfer(position, x.begin(), x.end());
}
//将 i 所指元素接合于 position 所指位置之前, position 和 i 可指向同一个 List
void splice (iterator position, list&, iterator i)
{
iterator j = i;
++j;
if(position == i || position == j) return; //如果 position 就是 i 本身,或者 i 本来就在 position 前面 ,则返回空
transfer(position, i, j);
}
//将 [first, last) 内的所有元素接合于 position 所指位置之前
// position 和 [first, last) 可能指向同一个 list
// 但 position 不能位于 [first, last) 之内
void splice (iterator position, list&, iterator first, iterator last)
{
if (first != last)
transfer(position, first, last);
}
//merge() 将 x 合并到 *this 身上,俩个 lists 的内容都必须先经过递增排序
template<class T, class Alloc>
void list<T, Alloc>::merge(list<T, Alloc>& x)
{
iterator first1 = begin();
iterator last1 = end();
iterator first2 = x.begin();
iterator last2 = x.end();
//注意,前提是,俩个Lists都已经过递增排序
while (first1 != last1 && first2 != last2)
if(*first2 < *first1)
{
iterator next = first2;
transfer (first1, first2, ++next);
first2 = next;
}
else
++first1;
if(first2 != last2) transfer (last1, first2, last2);
}
//reverse() 将 *this 的内容逆向重置
template<class T, class Alloc>
void list<T, Alloc>::reverse()
{
//以下判断,如果是空链表,或仅有一个元素,就不进行任何操作
//使用 size()==0 || size()==1 来判断,虽然也可以,但是比较慢
if(node->next == node || link_type(node->next)->next == node)
return ;
iterator first = begin();
++first;
while(first != end())
{
iterator old = first;
++first;
transfer(begin(), old, first);
}
}
// list 不能使用STL算法 sort() 必须使用自己的 sort() member function
//因为 STL 算法 sort() 只接受 RamdonAccessIterator
//**本函数采用 quick sort**
template< class T, class Alloc>
void list <T, Alloc>::sort()
{
//以下判断,如果是空链表,或仅有一个元素,就不进行任何操作
//使用 size()==0 || size()==1 来判断,虽然也可以,但是比较慢
if(node->next == node || link_type(node->next)->next == node)
return ;
//一些新的 lists ,作为中介数据存放区
list<T, Alloc> carry;
list<T, Alloc> counter[64];
int fill = 0;
while (!empty())
{
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]);
}