STL 中的链表排序
一直以来学习排序算法, 都没有在链表排序上下太多功夫,因为用得不多。最近看STL源码,才发现,原来即使是链表,也能有时间复杂度为O(nlogn)的算法,
大大出乎我的意料之外,一般就能想到个插入排序。
下面的代码就是按照源码写出的(去掉了模板增加可读性),注意forward_list是C++11新加的单向链表,这里选这个是因为它更接近我们自己实现链表时的做法。
void sort_list(forward_list<int>& l){
auto it = l.begin();
if (l.empty() || ++it == l.end())
return;
forward_list<int> carry;
forward_list<int> counter[64];//总共只设立了64个桶,因为第i个桶被填充的时候,里面至多2^i个元素,2^64,远超一般元素数目
int fill = 0; //fill记录的是当前填到哪个桶了
while (!l.empty()){
carry.splice_after(carry.cbefore_begin(), l, l.cbefore_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]);
l.swap(counter[fill - 1]);
}
关于此算法的分析:网上很多争论这个到底是快速排序还是归并排序的(侯捷的书上说是快排)。
为了理解这个代码,可以手动运行一下。
fill,记录用到了几个桶,最外层循环保证这样一个事实:从第0个桶到第fill - 1个桶里面,要么为空,要么存储有2^fill个元素,而且是有序链表。
每次与新取下的元素(存储在carry中)合并的桶都是counter[0]。如果第0个桶里没有元素,那就直接放进去carry.swap(counter[i])。下一轮循环的
时候,因为counter[0]里有元素了,就会进入内层循环,这时候,counter[i].merge(carry)使得第0个桶变为一个含两个元素的链表,然后内层循环第二步,又将这个链表
转移到carry中,下一轮内层循环的时候,带有两个元素的carry就会争取与第1个桶合并(如果第1个桶不空的话),如果第一个桶为空,它将退出内层循环并将元素放进第一个桶,(此时发现i == fill,于是fill变为2)然后下一轮外层循环继续从链表中取下一个元素,(此时counter[0]为空,counter[1]中含有两个元素),如前面一样,先是发现counter[0]是空的,进不去内层循环,于是直接把元素填到counter[0]中,下一次外层循环又取一个元素,进入内层循环,与counter[0]合并,交换,然后下一轮内层循环中,带有两个元素的carry就会与带有两个元素的counter[1]合并,交换, i == fiil == 2退出内层循环,四个元素变到第2个桶中,fill++。
走完这一遍之后,感觉清晰了,但是除了外层循环的循环不变条件以外,实在是很难从基本的快排或归并排序的思想中想到这样去做。
STL 中的链表排序的更多相关文章
- stl中常用的排序算法
#include"iostream" #include"vector" using namespace std; #include"string&qu ...
- STL中六大组件
1)容器(Container),是一种数据结构,如list,vector,和deques ,以模板类的方法提供.为了访问容器中的数据,可以使用由容器类输出的迭代器: 容器(container)用于存放 ...
- C++的标准模板库STL中实现的数据结构之链表std::list的分析与使用
摘要 本文主要借助对C++的标准模板库STL中实现的数据结构的学习和使用来加深对数据结构的理解,即联系数据结构的理论分析和详细的应用实现(STL),本文是系列总结的第二篇.主要针对线性表中的链表 ST ...
- C++ STL中Map的按Key排序和按Value排序
map是用来存放<key, value>键值对的数据结构,可以很方便快速的根据key查到相应的value.假如存储学生和其成绩(假定不存在重名,当然可以对重名加以区 分),我们用map来进 ...
- C++ STL中Map的相关排序操作:按Key排序和按Value排序 - 编程小径 - 博客频道 - CSDN.NET
C++ STL中Map的相关排序操作:按Key排序和按Value排序 - 编程小径 - 博客频道 - CSDN.NET C++ STL中Map的相关排序操作:按Key排序和按Value排序 分类: C ...
- STL中vector的赋值,遍历,查找,删除,自定义排序——sort,push_back,find,erase
今天学习网络编程,那个程序中利用了STL中的sort,push_back,erase,自己没有接触过,今天学习一下,写了一个简单的学习程序.编译环境是VC6.0 这个程序使用了vect ...
- STL中sort排序算法第三个参数_Compare的实现本质
关于C++ STL vector 中的sort排序算法有三种自定义实现,它们本质上都是返回bool类型,提供给sort函数作为第三个参数. 重载运算符 全局的比较函数 函数对象 我认为从实现方式看,重 ...
- C++ STL中Map的按Key排序
为了实现快速查找,map内部本身就是按序存储的(比如红黑树).在我们插入<key, value>键值对时,就会按照key的大小顺序进行存储.这也是作为key的类型必须能够进行<运算比 ...
- STL中的排序算法
本文转自:STL中的排序算法 1. 所有STL sort算法函数的名字列表: 函数名 功能描述 sort 对给定区间所有元素进行排序 stable_sort 对给定区间所有元素进行稳定排序 ...
随机推荐
- CRF++使用说明
摘选自 :CRF++: Yet Another CRF toolkit Usage: 1.输入输出文件 He PRP B-NP reckons VBZ B-VP the DT B-NP current ...
- JAVA图像缩放处理
http://www.blogjava.net/kinkding/archive/2009/05/23/277552.html ———————————————————————————————————— ...
- git 入门一(初识)
分布式版本控制系统 & 集中式版本控制系统 分布式版本控制系统( Distributed Version Control System)在这类系统中,像 Git,Mercurial,Baz ...
- Enterprise Architect UML建模
UML建模 前言 UML建模资料已经很多了,有人想用有人不用,有人会用也有人不会用,本文只是作者的一篇UML建模总结,不想去写太细,因为真正的你去用下,去画下就基本都会了.工具毕竟是工具,设计和思想才 ...
- Educational Codeforces Round 22 E. Army Creation 主席树 或 分块
http://codeforces.com/contest/813/problem/E 题目大意: 给出长度为n的数组和k, 大小是1e5级别. 要求在线询问区间[l, r]权值, 权值定义为对于 ...
- ubuntu终端使用代理
sudo http_proxy=http://your_proxy:proxy_port dropbox start -i or sudo https_proxy=http://your_proxy: ...
- Oracle11g Active Data Guard搭建、管理
说明:參考网络众多人的笔记及思路,加上自己亲身实践之后的整理笔记.仅供參考. Data Guard与RAC不同的是.在普通情况下.Standby仅仅有一个节点处于活动状态,全部的应用都连接到主serv ...
- cxGrid 使用指南 1
1:cxgrid是应该数据关联的控件,类似dbgrid.2:一般用来查阅表信息,如果要修改的话,直接在上面编辑或添加 非常不方便通常要放几个EDit来对选中的记录进行编辑或添加记录. 因为表一般都有主 ...
- FBV和CBV的差异
FBV FBV(function base views) 就是在视图里使用函数处理请求. 在之前django的学习中,我们一直使用的是这种方式,所以不再赘述. CBV CBV(class base ...
- 存一些可能会用得到的vue的UI框架
VUX 项目主页:https://vux.li/#/ github地址:https://github.com/airyland/vux element UI(饿了么后台) Element 是由饿了么U ...