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 对给定区间所有元素进行稳定排序 ...
随机推荐
- maven项目打ZIP包
1.Maven插件配置: <!-- ZIP打包 --> <plugin> <artifactId>maven-assembly-plugin</artifac ...
- 机器学习之svm---cv wiki svm
http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/ml/introduction_to_svm/introduction_to_s ...
- CentOS7.1 安装Liberty之环境准备(1)
一.基础平台 1.一台装有VMware的windows系统(可联网) 2.CentOS 7.1 64bit镜像 二.最小化安装两台CentOS 7.1 的虚拟机controller.compute1, ...
- Oracle性能监控脚本(sql)
1. 监控事例的等待 select event,sum(decode(wait_Time,0,0,1)) "Prev", sum(decode(wait_Time,0,1,0)) ...
- 设置label中的对齐方式
QLabel.setAlignment (self, Qt.Alignment) 下面查看Qt.Alignment: Qt.AlignmentFlag This enum type is used t ...
- python序列中添加高斯噪声
def wgn(x, snr): snr = 10**(snr/10.0) xpower = np.sum(x**2)/len(x) npower = xpower / snr return np.r ...
- 通用且常用的Java正则匹配工具,用以检查邮箱名、电话号码、用户密码、邮政编码等合法性
一个通用且常用的Java正则匹配工具,用以检查邮箱名.电话号码.用户密码.邮政编码等合法性. import java.util.regex.Matcher; import java.util.rege ...
- Vue.js_判断与循环
一.判断,条件语句 1.一元表达式判断 {{ ok ? 'show' : 'hide' }} 2.if判断 v-if='ok' <ol id="ifGrammar"> ...
- 封装IP池和用户代理相应的类(python3)
一.middlewares.py源代码: # -*- coding: utf-8 -*- # 导入随机模块 import random # 导入有关IP池有关的模块 from scrapy.contr ...
- monggodb 模糊查询
MongoDB的模糊查询其实很简单: 11.LIKE模糊查询userName包含A字母的数据(%A%) SQL:SELECT * FROM UserInfo WHERE user ...