侯捷STL源码解析:void list<T, Alloc>::sort()

本文详细解释了STL容器list的非递归归并排序算法,通过counter数组进行动态规划和数据合并,优化了空间复杂度,总时间复杂度为N*lgN。核心是利用carry作为临时缓存,counter存储逐步合并后的有序序列。
摘要由CSDN通过智能技术生成

下面是STL的容器list的结尾篇的对list数组的排序

template <class T, class Alloc>
void list<T, Alloc>::sort() {
 // 以下判断,如果是空白串行,或仅有一个元素,就不做任何动作。
 // 使用 size() == 0 || size() == 1来判断,虽然也可以,但是比较慢。
 if (node->next == node || link_type(node->next)->next == node)
 return;
 // 一些新的 lists,做为中介数据存放区
 list<T, Alloc> carry;
 list<T, Alloc> counter[64];
 int fill = 0;
 while (!empty()) {
 carry.splice(carry.begin(), *this, begin());
 int i = 0;
 while(i < fill && !counter[i].empty()) {
 counter[i].merge(carry);
 carry.swap(counter[i++]);
 }
 carry.swap(counter[i]);
 if (i == fill) ++fill;
 }
 for (int i = 1; i < fill; ++i)
 counter[i].merge(counter[i-1]);
swap(counter[fill-1]);
} 

排序方法:这里进行一下勘误,这不是快速排序,而是归并排序
为什么不递归直接归并排序:直接递归O(N)的空间复杂度,对于内存来说还是有负担的
时间复杂度:假设总元素个数N=2^n-1。

首先merge函数的复杂度为O(m),因此最后一步的for循环复杂度为 求和i:2~n{2^i-1}=O(N)的时间。

再看do_while循环,tmp[0]有1个元素,tmp[1]有2个元素,。。。,tmp[n-1]有2(n-1)个元素,他们都是通过merge而后再swap(为常数时间)到最终层次的,因此总复杂度为:求和i:1~n{i*2(i-1)}=O((n-1)2^n)=O(NlgN)。
因此总时间复杂度为N*lgN。
原理:fill ------> 2^fill 表示能处理的数据的最大数目,fill这里最大=64
counter[ fill ]—> 将处理完的2^fill个数据存入 counter[ fill ]中
carry—> 就像一个临时中转站, 在处理的数据不足 2 ^ fil l时,在counter[ i ] ( 0=<i<fill)之间移动数据(改变指针)

步骤如下:

  1. 读入一个数据(carry.splice),通过 carry 将数据存入 counter[0] 中;
    随后处理下一个数据, carry 保存数据
    a. counter[0].merge(carry) , 此时 counter[0] 容纳的数据个数 > 2^0
    b. 将counter[0]链中的数据,通过carry,转移到counter[1]链,… 直至处理的数据个数达到 2 ^ fill

  2. fill++ , 重复 1) 至处理完所有的数据。

非递归的快速排序实现方式,很巧妙!!!
counter 数组为64 — 所以此算法,一次最多能处理 2 ^ 64 -2 个数据

**梳理:**其实相当于carry是一个缓存list,counter是一个动态规划的数组list,counter[i]=counter[i-1]+carry,这里的“+”代表的是merge,也就是两个有序数组的合并。

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值