list-链表
list 设计
每个元素都是放在同一块内存中,它的内存空间可以是不连续的,通过指针来进行数据的访问。
添加删除元素的性能很高,通常用来作随机插入和删除操作的容器
list 属于双向链表,其结点与list本身是分开设计的。
template<class T, class Alloc = alloc>
class list {
protected:
typedef: listnode <T> listnode;
public:
typedef: listnode link_type;
typedef: listiterator<T, T &, T> iterator;
protected:
link_type node;
}
学习到了一个分析方法
,拿到这样一个类,先看它的数据比如上面的linktype node
,然后我们再看它的前缀linktype
,去上面在linktype
,找到typedef list_node linktype
;按这个方法继续找到上面的typedef listnode<T> listnode
;我们发现listnode
是下面的类,我们一层层寻找,就能看懂这些源码:
template<class T>
struct _listnode {
typedef void voidpointer;
voidpointer prev;
voidpointer next;
T data;
}
list 是一个环状的双向链表,同时它也满足STL对于“前闭后开”
的原则,即在链表尾端可以加上空白节点。
list迭代器的设计:
迭代器是繁华的指针,所以里面重载了->
, --
, ++
, *
, ()
等运算符,同时迭代器是算法与容器之间的桥梁,算法需要了解容器的方方面面,于是就诞生了5种关联类型
(这5种是必须的,可能还需要其他的类型)。我们知道算法传入的是迭代器或者指针,算法根据传入的迭代器或指针推断出算法所想要的了解的容器里的5种关联类型的相关信息。由于只传入指针,算法推断不出来想要的信息,所以我们需要一个中间商(萃取器),也就是我们所说的iterator traits
类,对于一般的得带器,它直接提供迭代器里的关联类型值,而对于指针和常量指针,它采用的类模板偏特化,从而提供其所需要的关联类型的值。
// 针对⼀般的迭代器类型,直接取迭代器内定义的关联类型
template<class I>
struct iterator_traits {
typedef typename I::iteratorcategory iteratorcategory;
typedef typename I::valuetype valuetype;
typedef typename I::differencetype differencetype;
typedef typename I::pointer pointer;
typedef typename I::reference reference;
};
//• 针对指针类型进⾏特化,指定关联类型的值
template<class T>
struct iteratortraits<T> {
typedef randomaccessiteratortag iteratorcategory;
typedef T value_type;
typedef ptrdifft differencetype;
typedef T *pointer;
typedef T &reference;
};
//• 针对指针常量类型进⾏特化,指定关联类型的值
template<class T>
struct iteratortraits<const T> {
typedef randomaccessiteratortag iteratorcategory;
typedef T valuetype; // valuetye被⽤于创建变量,为灵活起⻅,取 T ⽽⾮ const T 作为value_type
typedef ptrdifft differencetype;
typedef const T *pointer;
typedef const T &reference;
};
vector 和 list的区别
- 底层现实不同:vector底层实现是数组,list是双向链表;
- vector是顺序内存,支持随机访问,list是链表,不支持随机访问;
- vector 在中间节点进行插入、删除会导致内存拷贝,list不会;
- vector一次性分配好内存,内存不够再进行扩容;list每次插入新节点都会申请新内存;
- vector随机访问性能好,插入删除性能差;list随机访问性能差,插入删除性能好。