下面是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)之间移动数据(改变指针)
步骤如下:
-
读入一个数据(carry.splice),通过 carry 将数据存入 counter[0] 中;
随后处理下一个数据, carry 保存数据
a. counter[0].merge(carry) , 此时 counter[0] 容纳的数据个数 > 2^0
b. 将counter[0]链中的数据,通过carry,转移到counter[1]链,… 直至处理的数据个数达到 2 ^ fill -
fill++ , 重复 1) 至处理完所有的数据。
非递归的快速排序实现方式,很巧妙!!!
counter 数组为64 — 所以此算法,一次最多能处理 2 ^ 64 -2 个数据
**梳理:**其实相当于carry是一个缓存list,counter是一个动态规划的数组list,counter[i]=counter[i-1]+carry,这里的“+”代表的是merge,也就是两个有序数组的合并。