list 的 sort 算法
由于 STL 本身的排序算法 sort 接受的输入迭代器是随机访问迭代器,但是双向 list 链表容器的访问方式是双向迭代器,因此,不能使用 STL 本身的排序算法 sort,必须自己定义属于自己访问的排序算法。
template <class _Tp, class _Alloc>
void list<_Tp, _Alloc>::sort()
{
//@ 如果链表为空或者链表只有一个元素则不做任何操作
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())
{//@ 若不是空链表
//@ step1:
//@ 把当前链表的第一个节点放在 carry 链表头
__carry.splice(__carry.begin(), *this, begin());
int __i = 0;
while(__i < __fill && !__counter[__i].empty())
{
//@ step2:
__counter[__i].merge(__carry); //@ 把链表carry合并到counter[i]
//@ step3:
__carry.swap(__counter[__i++]); //@ 交换链表carry和counter[i]内容
}
//@ step4:
__carry.swap(__counter[__i]); //@ 交换链表carry和counter[i]内容
//@ step5:
if (__i == __fill) ++__fill;
}
for (int __i = 1; __i < __fill; ++__i)
//@ step6:
//@ 把低位不满足进位的剩余数据全部有序的合并到上一位
__counter[__i].merge(__counter[__i-1]);
//@ step7:
//@ 最后把已排序好的链表内容交换到当前链表
swap(__counter[__fill-1]);
}
}
图解 list sort 算法
待排序的原始链表:
-
第一次执行 while 循环
- 执行步骤 step1:carry 取出当前链表的第一个数据节点 7。
- 执行步骤 step4:交换 carry 和 counter 的内容。
- 执行步骤 step5:更新 fill 值,fill=1。
-
第二次执行 while 循环
- 执行步骤 step1:carry 取出当前链表的第一个数据节点 5。
- 执行步骤 step2:将 carry 链表的内容有序的合并到 counter 链表中。
- 执行步骤 step3:交换 carry 和 counter[0] 内容且 i++。
- 执行步骤 step4:交换carry 和 counter[1] 的内容。
- 执行步骤 step5:更新 fill 的值,fill=2。
-
第三次执行 while 循环
- 执行步骤 step1:carry 取出当前链表的第一个数据节点 8。
- 执行步骤 step4:交换 carry 和 counter[0] 的内容。
-
第四次执行while循环:
- 执行步骤 step1:carry 取出当前链表的第一个数据节点 1。
- 执行步骤 step2:将 carry 链表的内容有序的合并到 counter[0] 链表中。
- 执行步骤 step3:交换 carry 和 counter[0] 内容且 i++。
- 再执行步骤 step2:将 carry 的内容有序的合并到 counter[1] 链表中。
- 再执行步骤step3:交换 carry 和 counter[1] 的内容且 i++。
- 执行步骤 step4:交换carry 和 counter[2] 的内容。
- 执行步骤 step5:更新 fill 的值,fill=3。
-
最后
- 执行步骤 step6:合并 counter。
- 执行步骤 step7:交换当前链表和 counter[2] 。