目录
list是一个循环双向链表, 不是一个连续地址空间, 所以sort功能需要特殊的算法单独实现, 而不能用算法中的sort. 当然还可以将list的元素插入到vector中最后将vector排序好的数据拷贝回来, 不过这种做法很费时, 费效率
先分析几个会被调用的函数
功能:将一段链表添加到指定位置之前
last的前一个节点叫last_but_onefirst的前一个节点叫zero现在分析transfer的每一步

- template <class T, class Alloc = alloc>
- class list
- {
- ...
- protected:
- void transfer(iterator position, iterator first, iterator last)
- {
- if (position != last)
- {
- (*(link_type((*last.node).prev))).next = position.node;
- (*position.node).prev = (*last.node).prev;
- link_type tmp = link_type((*position.node).prev);
- (*first.node).prev = tmp;
- (*(link_type((*position.node).prev))).next = first.node;
- (*(link_type((*first.node).prev))).next = last.node;
- (*last.node).prev = (*first.node).prev;
- }
- }
- /*
- void transfer(iterator position, iterator first, iterator last)
- {
- if (position != last)
- {
- (*(link_type((*last.node).prev))).next = position.node;
- (*(link_type((*first.node).prev))).next = last.node;
- (*(link_type((*position.node).prev))).next = first.node;
- link_type tmp = link_type((*position.node).prev);
- (*position.node).prev = (*last.node).prev;
- (*last.node).prev = (*first.node).prev;
- (*first.node).prev = tmp;
- }
- }
- */
- ...
- };
splice 将两个链表进行合并(调用了transfer)
- template <class T, class Alloc = alloc>
- class list
- {
- ...
- public:
- void splice(iterator position, list& x) {
- if (!x.empty())
- transfer(position, x.begin(), x.end());
- }
- void splice(iterator position, list&, iterator i) {
- iterator j = i;
- ++j;
- if (position == i || position == j) return;
- transfer(position, i, j);
- }
- void splice(iterator position, list&, iterator first, iterator last) {
- if (first != last)
- transfer(position, first, last);
- }
- ...
- };
将list与x从小到大合并到原链表中(核心还是transfer)
- template <class T, class Alloc>
- void list
::merge(list& x) { - iterator first1 = begin();
- iterator last1 = end();
- iterator first2 = x.begin();
- iterator last2 = x.end();
- while (first1 != last1 && first2 != last2)
- if (*first2 < *first1) {
- iterator next = first2;
- // 将first2到first+1的左闭右开区间插入到first1的前面
- // 这就是将first2合并到first1链表中
- transfer(first1, first2, ++next);
- first2 = next;
- }
- else
- ++first1;
- // 如果链表x还有元素则全部插入到first1链表的尾部
- if (first2 != last2) transfer(last1, first2, last2);
- }
功能:翻转链表
list的迭代器不会改变
将每个元素一个一个插入到begin之前(list不会变但begin()会变,它始终指向第一个元素的地址)
- template <class T, class Alloc>
- void list
::reverse() - {
- if (node->next == node || link_type(node->next)->next == node)
- return;
- iterator first = begin();
- ++first;
- while (first != end()) {
- iterator old = first;
- ++first;
- // 将元素插入到begin()之前
- transfer(begin(), old, first);
- }
- }
几个重要参数分析
fill : 当前可以处理的元素个数为2^fill个
counter[fill] : 可以容纳2^(fill+1)个元素
carry : 一个临时中转站, 每次将一元素插入到counter[i]链表中.
在处理的元素个数不足2^fill个时,在counter[i](0之前转移元素
步骤:
每次读一个数据到carry中,并将carry的数据转移到counter[0]中
当counter[0]中的数据个数少于2时,持续转移数据到counter[0]中
当counter[0]的数据个数等于2时,将counter[0]中的数据转移到counter[1]…从counter[i]转移到counter[i+1],直到counter[fill]中数据个数达到2^(fill+1)个。
++fill, 重复步骤1sort用了一个数组链表用来存储2^i个元素, 当上一个元素存储满了之后继续往下一个链表存储, 最后将所有的链表进行merge归并(合并), 从而实现了链表的排序!
- //list 不能使用sort函数,因为list的迭代器是bidirectional_iterator, 而sort
- //sort函数要求random_access_iterator
- template<class T,class Alloc>
- void list
::sort() - {
- //如果元素个数小于等于1,直接返回
- if(node->next==node||node->next->next==node)
- return ;
- list
carry; //中转站 - list
counter[64]; - int fill=0;
- while(!empty())
- {
- carry.splice(carry.begin(),*this,begin()); //每次取出一个元素
- int i=0;
- while(i
empty()) - {
- counter[i].merge(carry); //将carry中的元素合并到counter[i]中
- carry.swap(counter[i++]); //交换之后counter[i-1]为空
- }
- carry.swap(counter[i]);
- if(i==fill)
- ++fill;
- }
- // 将counter数组链表的所有节点按从小到大的顺序排列存储在counter[fill-1]的链表中
- for(int i=1;i
- {
- counter[i].merge(counter[i-1]);
- }
- // 最后将couter与carry交换, 实现排序
- swap(counter[fill-1]);
- }
本篇文章有图解:(36条消息) stl中list的sort()函数解析_骑猪去兜风..的博客-CSDN博客_list sort stl
总结:
