之前接触到的数组以及vector,在内存上都是连续的。
而链表list是一种物理存储单元上非连续的存储结构。数据元素的逻辑顺序是通过链表中的指针链接实现的。
链表的组成:
- 链表是由一系列结点组成。
结点的组成:
- 第一部分是存储数据元素的数据域;
- 第二部分是存储下一个结点地址的指针域。
链表的实现方式:
数组是在一片连续的物理内存空间中。
而链表是由结点构成,每个结点的位置不一定连续,每个结点由两部分组成:一部分是数据域,用来存放我们实际要操作的数据,另一部分是指针域,指向下一个结点的地址。通过指针域链接使得整个链表看起来像是连续的一样。
链表的优点:
- 链表采用动态存储分配,不会造成内存浪费和溢出。有多少用多少。
- 在vector中,我们测试10万数据,大概需要开辟13万的容量,造成了资源的浪费。
- 链表中,10万个数,就是10万个结点。
- 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素。可以对任意位置进行快速的插入或删除元素。
数组和vector等为了插入和删除都需要搬移大量的数据。很麻烦。而链表只需要插入或者删除一个结点,修改一下指针指向就可以了。
链表的缺点:
- 缺点一:容器遍历速度,没有数组和vector快。因为查找下一个元素,必须要去指针域查看。
- 这个速度慢,就像是我们采用了deque(支持头插。双端数组。)之后,由于需要去中控器里面找下一段缓冲区的位置,所以导致了访问速度慢。
- 缺点而:占用的空间会比数组大。
数组的优点,就是链表的缺点,链表的优点,就是数组的缺点。
优缺点都是互补的。
基于数组的缺点,所以我们才会去创建这样一个数据结构,来弥补数组的缺点。补全了缺点,其本身相应付出的代价,也就成了其缺点。
STL中的链表是一个双向循环链表。
STL中链表的结点在指针域有两个指针:
- 一个指针指向前一个结点,
- 一个指针指向后一个结点。
所以说是双向的。
循环如何实现?
- 最后一个结点的后向指针指向第一个结点。第一个节点的前向指针指向最后一个结点的位置。
- 图中并没有表明。只是显示了指向为null的情况。
链表接口:
此外链表还提供了头插push_front()和头删pop_front(),尾插push_back()和尾删pop_back();
同时:还有迭代器中的begin()起始位置和end()最后元素的下一个位置,front()头元素和back()尾元素;支持insert();
双向迭代器:
由于链表的存储方式并不是连续的内存空间,因此链表的迭代器只支持前移和后移,属于双向迭代器。
只支持逐个前移和后移,因此不支持随机访问的那种跳跃式访问。
list重要特性:
插入操作和删除操作都不会造成原有list迭代器的失效,这在vector中是不成立的。
总结:
STL中List和Vector是两个最常被使用的容器,各有优缺点。