STL list sort 算法的非递归归并排序(模拟实现版)
看《STL源码剖析》的时候,看到书上说是quick sort, 但是怎么看都看不明白,因此就上网上找到了这篇文章,然后自己修改了一下代码,打印更详细的信息,方便自己理解。
这个排序 主要基于merge函数,merge 函数 将两个非递减list 合并为 一个非递减list。
// STLSort.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <list>
using namespace std;
void showCounter(list<int> *counter, int ilay)
{
cout << "当前counter: " << endl;
for (size_t i = 0; i <= ilay; i++)
{
cout << i << ": ";
for (auto it = counter[i].begin(); it != counter[i].end(); it++) {
cout << *it << " ";
}
cout << endl;
}
}
// list<T>.sort()等价外部实现,用到了归并排序的算法思想
void sortList(list<int> &a) {
if (a.size() <= 1){
return;
}
list<int> carry; // 辅助链表,用于从a中提取元素以及临时保存两个链表的合并结果
list<int> counter[64]; // 保存着当前每一个归并层次的结果, i号链表保存的元素个数为2的i次方或者0
int fill = 0; // 表示当前最大归并排序的层次,while循环之后fill变成log2(a.size())
while (!a.empty()) {
carry.splice(carry.begin(), a, a.begin()); // 将链表a中的第一个元素移动至carry开头
cout << "carry 取到新值:" << *carry.begin() << endl;
int i = 0;
// 从小往大不断合并非空归并层次直至遇到空层或者到达当前最大归并层次
while (i < fill && !counter[i].empty()) {
counter[i].merge(carry); // 链表合并,结果链表是有序的,必须保证合并前两个链表是有序的
cout << endl;
showCounter(counter, fill);
carry.swap(counter[i++]); // 链表元素互换
}
carry.swap(counter[i]); //carry 将数据放入 下一个空层
cout << endl;
showCounter(counter, fill);
if (i == fill) { // i到达当前最大归并层次,说明得增加一层
++fill;
}
}
for (int i = 1; i < fill; ++i) { // 将所有归并层次的结果合并得到最终结果counter[fill - 1]
counter[i].merge(counter[i - 1]);
}
showCounter(counter, fill);
a.swap(counter[fill - 1]);
}
int _tmain(int argc, _TCHAR* argv[])
{
list<int> test;
test.push_back(8);
test.push_back(6);
test.push_back(520);
test.push_back(27);
test.push_back(124);
test.push_back(214);
test.push_back(688);
test.push_back(12);
test.push_back(36);
cout << "排序前" << endl;
for (auto i = test.begin(); i != test.end(); i++) {
cout << *i << " ";
}
sortList(test);
cout << endl << "排序后:" << endl;
for (auto i = test.begin(); i != test.end(); i++) {
cout << *i << " ";
}
cout << endl;
system("pause");
return 0;
}
打印结果及解释
排序前
8 6 520 27 124 214 688 12 36
1、carry 取新值 8,当前合并层次fill为0,因此直接把数据放入第一层
carry 取到新值:8
当前counter:
0: 8
2、carry 取新值,当前合并层次fill为1,且第一层有数据 8,因此合并,合并后 为: 6 8,然后carry 取合并后的6 8 试图合并 下一层结果发现:i = fill,已经合并到最大层,因此退出合并循环,并将数据放入 下一层
carry 取到新值:6
当前counter:
0: 6 8
1:
当前counter:
0:
1: 6 8
3、carry 取新值,当前合并层次fill 为2,但是 第一层没有数据,因此carry 将数据放入第一层,并进入下一次取数据循环
carry 取到新值:520
当前counter:
0: 520
1: 6 8
2:
4、carry 取新值,当前合并层次仍然 为2,因为上一次循环并未合并数据;
(1)carry将自己数据和 第一层数据合并,合并后为:27 520, carry 取走合并后的数据
(2)carry 试图合并下一层,发现i 未达到最大合并层次,并且下一层有数据,因此 合并,合并后的数据为:6 8 27 520, carry 取走合并后的数据
(2)carry 试图合并下一层,发现已经达到最大合并层次,并且下一层为空,直接退出while 循环,并将数据放入下一层中。
carry 取到新值:27
当前counter://(1)
0: 27 520
1: 6 8
2:
当前counter://(2)
0:
1: 6 8 27 520
2:
当前counter://(3)
0:
1:
2: 6 8 27 520
5、carry 取新值,当前合并层次为 3;carry合并数据的时候发现,第一层为空,因此直接将数据放入第一层。
carry 取到新值:124
当前counter:
0: 124
1:
2: 6 8 27 520
3:
6、carry 取新值,当前合并层次仍然为 3;carry合并数据的时候发现,
(1)第一层不为空,因此合并,合并数据为 124 214, carry 取走合并后的数据。
(2)carry 试图合并第二层,发现第二层数据为空,因此直接退出while循环,并将数据放入 第二层。
carry 取到新值:214
当前counter:
0: 124 214
1:
2: 6 8 27 520
3:
当前counter:
0:
1: 124 214
2: 6 8 27 520
3:
7、carry 取到新数据,当前合并层次仍然为3;carry合并数据的时候发现第一层为空,因为直接将数据放入第一层。
carry 取到新值:688
当前counter:
0: 688
1: 124 214
2: 6 8 27 520
3:
8、carry 去到新数据,当前合并层次仍然为3;carry 合并数据时候发现:
(1)第一层不为空,合并,合并后为:12 688;并取走合并后的数据;
(2)第二层不为空,合并,合并后为:12 124 214 688;并取走合并后的数据;
(3)第三层不为空,合并,合并后为:6 8 12 27 124 214 520 688;并取走合并后的数据。
(4)试图合并第四层,发现i已经达到当前合并层次,因此退出while 循环,直接将数据放入下一层。
carry 取到新值:12
当前counter://(1)
0: 12 688
1: 124 214
2: 6 8 27 520
3:
当前counter://(2)
0:
1: 12 124 214 688
2: 6 8 27 520
3:
当前counter://(3)
0:
1:
2: 6 8 12 27 124 214 520 688
3:
当前counter://(4)
0:
1:
2:
3: 6 8 12 27 124 214 520 688
9、carry 取新数据,发现第一层为空,直接将数据丢入第一层。
carry 取到新值:36
当前counter:
0: 36
1:
2:
3: 6 8 12 27 124 214 520 688
4:
10、待排序列表a 中已经无数据可取,遍历counter, 合并所有层次
当前counter:
0:
1:
2:
3: 6 8 12 27 36 124 214 520 688
4:
排序后:
6 8 12 27 36 124 214 520 688