STL学习笔记--4序列式容器之list
Posted chengyu779394084
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STL学习笔记--4序列式容器之list相关的知识,希望对你有一定的参考价值。
1、概述
list:地址不连续的空间。每次插入或删除一个元素,就配置或释放一个元素空间。对于任意位置的元素插入或删除,list永远是常数时间。
2、list节点
list本身和list节点是不同的;
template <class T>
struct __list_node {
typedef void* void_pointer;
//void_pointer实际为__list_node<T>*
void_pointer next;
void_pointer prev;
T data;
};
双向链表。
3、list迭代器
list迭代器必须有能力指向list的节点;
递增:指向下一个节点
递减:指向上一个节点
取值:取得是节点的数据值
成员取用:取得是节点的成员
STL的list是双向链表;迭代器提供的为Bidirectional Iterators。
插入insert和接合splice操作不会使原有list的迭代器失效。
删除只会使指向删除元素的迭代器失效。
template<class T, class Ref, class Ptr>
struct __list_iterator {
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, Ref, Ptr> self;
//迭代器提供的是BidirectionaIterator
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
//link_type为node的指针
typedef __list_node<T>* link_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
link_type node;
//构造函数
__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; }
//取值取得是节点的数据值
reference operator*() const { return (*node).data; }
//成员取用取得是节点的成员
pointer operator->() const { return &(operator*()); }
//前置++,指向下一个节点
self& operator++() {
node = (link_type)((*node).next);
return *this;
}
//后置++
self operator++(int) {
self tmp = *this;
++*this;
return tmp;
}
self& operator--() {
node = (link_type)((*node).prev);
return *this;
}
self operator--(int) {
self tmp = *this;
--*this;
return tmp;
}
};
4、list的数据结构
SGI的list不仅是双向链表,更是一个环形双向链表。
让指针node指向尾端的空白节点,则符合前闭后开的区间要求。
template <class T, class Alloc = alloc>
class list {
protected:
typedef void* void_pointer;
typedef __list_node<T> list_node;
protected:
link_type node;//指向尾段空白节点
//...
public:
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迭代器的成员函数
distance(begin(), end(), result);
return result;
}
reference front() { return *begin(); }
reference back() { return *(--end()); }
};
5、list的构造和内存管理
1)、应用:
#include <list>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
list<int> ilist;
cout << "size=" << ilist.size() << endl; // size=0
ilist.push_back(0);
ilist.push_back(1);
ilist.push_back(2);
ilist.push_back(3);
ilist.push_back(4);
cout << "size=" << ilist.size() << endl; // size=5
list<int>::iterator ite;//声明迭代器
for(ite = ilist.begin(); ite != ilist.end(); ++ite)
cout << *ite << ' '; // 0 1 2 3 4
cout << endl;
//插入和接合操作不会造成原迭代器失效
ite = find(ilist.begin(), ilist.end(), 3);
if (ite != ilist.end())
ilist.insert(ite, 99);//在以前3的位置处插入一个数99,
//插入完成后,新节点位于ite所指节点前方
cout << "size=" << ilist.size() << endl; // size=6
cout << *ite << endl; // 3 !!!!
for(ite = ilist.begin(); ite != ilist.end(); ++ite)
cout << *ite << ' '; // 0 1 2 99 3 4
cout << endl;
//删除操作时,指向被删除元素的那个迭代器失效,其他不受影响
ite = find(ilist.begin(), ilist.end(), 1);
if (ite != ilist.end())
cout << *(ilist.erase(ite)) << endl;// 2 !!!
cout<<*ite<<endl;// 1 !!!
cout<<*(ite++)<<endl;// 1 !!!
for(ite = ilist.begin(); ite != ilist.end(); ++ite)
cout << *ite << ' '; // 0 2 99 3 4
cout << endl;
return 0;
}
2)、实现:
配置了list_node_allocator,方便以节点大小为单位来分配内存。
/*
//get_node()
//put_node()
//create_node()
//destroy_node()
//empty_initialize()
*/
template <class T, class Alloc = alloc>
class list {
protected:
typedef void* void_pointer;
typedef __list_node<T> list_node;
typedef simple_alloc<list_node, Alloc> list_node_allocator;
protected:
//配置一个节点
link_type get_node() { return list_node_allocator::allocate(); }
//释放一个节点
void put_node(link_type p) { list_node_allocator::deallocate(p); }
//产生一个节点,配置并构造,带有元素值x
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);
}
public:
//产生一个空链表
list(){empty_initialize();}
protected:
//只有一个node节点,且node的头尾都指向自己,元素值为空。
void empty_initialize() {
node = get_node();
node->next = node;
node->prev = node;
}
};
push_back(x)调用insert来实现。
void push_back(const T& x){insert(end(),x);}
insert()函数完成之后,新节点将位于哨兵迭代器(标识插入点)所直接点的前方。
//在position所指向的位置处插入一个节点,内容为x
iterator insert(iterator position, const T& x) {
//为插入内容构造节点
link_type tmp = create_node(x);
//修改迭代器的指向
//4步策略
tmp->next = position.node;
tmp->prev = position.node->prev;
(link_type(position.node->prev))->next = tmp;
position.node->prev = tmp;
return tmp;
}
6、元素操作
1)、实现:
/*
//push_front
//push_back
//erase
//pop_front
//pop_back
//clear
//remove(const T& value)将数值为value的所有元素移除
//unique()移除所有数值相同并且连续的元素。只有连续且相同的元素才会被移除的只剩一个
*/
void push_front(const T& x) { insert(begin(), x); }
void push_back(const T& x) { insert(end(), x); }
//删除position迭代器指向的位置处的节点
//返回为next_node
iterator 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);
}
void pop_front() { erase(begin()); }
//移除尾节点时,end()指向的是尾后节点
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;
//从头节点开始删除
while (cur != node) {
link_type tmp = cur;
cur = (link_type) cur->next;
destroy_node(tmp);
}
//最后一个节点头尾指向自身
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;
}
}
迁移操作transfer:将某个连续范围的元素迁移到某个特定的位置之前。
//transfer
//将[first,last)的所有元素放到position之前。
void transfer(iterator position, iterator first, iterator last) {
if (position != last) {
(*(link_type((*last.node).prev))).next = position.node;//1
(*(link_type((*first.node).prev))).next = last.node;//2
(*(link_type((*position.node).prev))).next = first.node;//3
link_type tmp = link_type((*position.node).prev);//4
(*position.node).prev = (*last.node).prev;//5
(*last.node).prev = (*first.node).prev; //6
(*first.node).prev = tmp;//7
}
}
transfer非公开接口。
list中提供了一些公开的接口,底层使用transfer来实现的。
- splice:将某个连续范围的元素从一个list移动到另一个(或同一个)list的某个定点。
- merge:将一个list合并到另一个list。两个list都必须先经过递增排序。
- reverse:将list的内容逆置。
- sort:排序。
2)、应用:
int iv[5] = { 5,6,7,8,9 };
list<int> ilist2(iv, iv+5);
// 目前,ilist 的內容为0 2 99 3 4
ite = find(ilist.begin(), ilist.end(), 99);//在99前面插入
ilist.splice(ite,ilist2); // 0 2 5 6 7 8 9 99 3 4
ilist.reverse(); // 4 3 99 9 8 7 6 5 2 0
ilist.sort(); // 0 2 3 4 5 6 7 8 9 99
总结:
- (1)push_front(const T& value), push_back(const T& value)
- (2)erase(iterator position):移除迭代器position所指节点
- (3)pop_front(), pop_back()
- (4)clear()://清空list节点
- (5)remove(const T& value):将数值为value的所有元素移除
- (6)unique():移除数值相同的连续元素,只剩下一个。注意相同而连续。
- (7)splice:接合操作。将某连续范围的元素从一个list移动到另一个(或同一个)list的某个定点。
- (8)merge(list &x):将x合并到*this身上。两个lists内容必须先递增排序。
- (9)reverse():将list的内容逆置。
- (10)sort():list不能使用STL算法sort(),必须使用自己的sort()成员函数,因为STL算法sort()只接受RamdonAccessIterator。list中sort()函数采用quicksort。
以上是关于STL学习笔记--4序列式容器之list的主要内容,如果未能解决你的问题,请参考以下文章