《STL源码剖析》---SGI STL list sort 算法

STL list sort 算法的非递归归并排序(模拟实现版)

原始代码转载自网络 : 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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,924评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,781评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,813评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,264评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,273评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,383评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,800评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,482评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,673评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,497评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,545评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,240评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,802评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,866评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,101评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,673评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,245评论 2 341

推荐阅读更多精彩内容