前言
由于STL本身的排序算法sort接受的输入迭代器是随机访问迭代器,但是双向list链表容器的访问方式是双向迭代器,因此,不能使用STL本身的排序算法sort,必须自己定义属于自己访问的排序算法。我们从源码的剖析中,可以看到该排序算法思想类似于归并排序。
list容器之排序算法sort
在该排序算法的实现过程中,定义了一个类似于搬运作用的链表carry和具有中转站作用的链表counter,这里首先对counter[i]里面存储数据的规则进行分析;counter[i]里面最多存储数据个数为,若存储数据超过该数字,则向相邻高位进位,即把counter[i]链表里的内容都合并到counter[i+1]链表。carry负责取出原始链表的头一个数据节点和交换数据中转站作用;源码中的fill表示当前可处理数据的个数为
。下面给出sort的源码分析:
//按升序进行排序,list链表的迭代器访问时双向迭代器
//因为STL的排序算法函数sort()是接受随机访问迭代器,在这里并不适合
template <class _Tp, class _Alloc>
void list<_Tp, _Alloc>::sort()
{
// Do nothing if the list has length 0 or 1.
if (_M_node->_M_next != _M_node && _M_node->_M_next->_M_next != _M_node)
{
list<_Tp, _Alloc> __carry;//carry链表起到搬运的作用
//counter链表是中间存储作用
/*
*其中对于counter[i]里面最多的存储数据为2^(i+1)个节点
*若超出则向高位进位即counter[i+1]
*/
list<_Tp, _Alloc> __counter[64];
int __fill = 0;
while (!empty())
{//若不是空链表
//第一步:
__carry.splice(__carry.begin(), *this, begin());//把当前链表的第一个节点放在carry链表头
int __i = 0;
while(__i < __fill && !__counter[__i].empty())
{
//第二步:
__counter[__i].merge(__carry);//把链表carry合并到counter[i]
//第三步:
__carry.swap(__counter[__i++]);//交换链表carry和counter[i]内容
}
//第四步:
__carry.swap(__counter[__i]);//交换链表carry和counter[i]内容
//第五步:
if (__i == __fill) ++__fill;
}
for (int __i = 1; __i < __fill; ++__i)
//第六步:
__counter[__i].merge(__counter[__i-1]);//把低位不满足进位的剩余数据全部有序的合并到上一位
//第七步:
swap(__counter[__fill-1]);//最后把已排序好的链表内容交换到当前链表
}
}
从源码中,我们可以看到,第一个while循环执行的条件是当前链表必须非空,该算法的核心就是while里面的处理,嵌套while(即第二个while)执行的条件是i小于fill</