STL 源码分析《2》----nth_element() 使用与源码分析
Select 问题: 在一个无序的数组中 找到第 n 大的元素。
思路 1: 排序,O(NlgN)
思路 2: 利用快排的 RandomizedPartition(), 平均复杂度是 O(N)
思路 3: 同样是利用快排的 Partition(), 但是选择 pivot 的时候不是采用随机,而是通过一种特殊的方法。从而使复杂度最坏情况下是 O(N)。
本文介绍 STL 算法库中 nth_elemnt 的实现代码。
STL 采用的算法是: 当数组长度 <= 3时, 采用插入排序。
当长度 > 3时, 采用快排 Partition 的思想;
一、使用说明
void
nth_element (RandomAccessIteratorbeg,
RandomAccessIterator
nth,
RandomAccessIterator
end)
void
nth_element (RandomAccessIterator beg,
RandomAccessIterator nth,
RandomAccessIterator end,
BinaryPredicate op)
1. 两个函数都是让 第 n 个位置上的元素就位,
所有在位置 n 之前的元素都小于或等于它,
所有在位置 n 之后的元素都大于或等于它。
2. 复杂度: 平均复杂度是 O(N)
以下例子是使用范例:
- // copyright @ L.J.SHOU Feb.23, 2014
- #include <iostream>
- #include <algorithm>
- #include <iterator>
- using namespace std;
- int main(void)
- {
- int a[]={3,5,2,6,1,4};
- nth_element(a, a+3, a+sizeof(a)/sizeof(int));
- cout << "The fourth element is: " << a[3] << endl;
- // output array a[]
- copy(a, a+sizeof(a)/sizeof(int),
- ostream_iterator<int>(cout, " "));
- return 0;
- }
程序输出结果:
The fourth element is: 4
2 1 3 4 6 5
二、源码分析
- // nth_element() and its auxiliary functions.
- template <class _RandomAccessIter, class _Tp>
- void __nth_element(_RandomAccessIter __first, _RandomAccessIter __nth,
- _RandomAccessIter __last, _Tp*) {
- while (__last - __first > 3) {
- _RandomAccessIter __cut =
- __unguarded_partition(__first, __last,
- _Tp(__median(*__first,
- *(__first + (__last - __first)/2),
- *(__last - 1))));
- if (__cut <= __nth)
- __first = __cut;
- else
- __last = __cut;
- }
- __insertion_sort(__first, __last);
- }
- template <class _RandomAccessIter>
- inline void nth_element(_RandomAccessIter __first, _RandomAccessIter __nth,
- _RandomAccessIter __last) {
- __STL_REQUIRES(_RandomAccessIter, _Mutable_RandomAccessIterator);
- __STL_REQUIRES(typename iterator_traits<_RandomAccessIter>::value_type,
- _LessThanComparable);
- __nth_element(__first, __nth, __last, __VALUE_TYPE(__first));
- }
- template <class _RandomAccessIter, class _Tp>
- _RandomAccessIter __unguarded_partition(_RandomAccessIter __first,
- _RandomAccessIter __last,
- _Tp __pivot)
- {
- while (true) {
- while (*__first < __pivot)
- ++__first;
- --__last;
- while (__pivot < *__last)
- --__last;
- if (!(__first < __last))
- return __first;
- iter_swap(__first, __last);
- ++__first;
- }
- }
_unguarded_partition 就是快排的 partition, 将数组分成两部分,左边的元素都小于或者等于 pivot, 右边的元素都大于或者等于 pivot.
从上述代码可以看出, nth_element 采用的 pivot 是 首元素,尾元素,中间元素,三个数的median.
通过_unguarded_partition 将数组分成两部分,
如果 nth 这个迭代器在左半边,则继续在左半边搜索;
若 nth 在右半边, 则在右半边搜索;
直到数组的长度 <= 3,时, 采用插入排序。这时 nth 迭代器所指向的数就归位了,而且它的左边元素都小于或者等于它, 右边元素都大于或者等于它。
STL 源码分析《2》----nth_element() 使用与源码分析的更多相关文章
- Spring源码分析——BeanFactory体系之抽象类、类分析(二)
上一篇分析了BeanFactory体系的2个类,SimpleAliasRegistry和DefaultSingletonBeanRegistry——Spring源码分析——BeanFactory体系之 ...
- Android7.0 Phone应用源码分析(二) phone来电流程分析
接上篇博文:Android7.0 Phone应用源码分析(一) phone拨号流程分析 今天我们再来分析下Android7.0 的phone的来电流程 1.1TelephonyFramework 当有 ...
- Android7.0 Phone应用源码分析(一) phone拨号流程分析
1.1 dialer拨号 拨号盘点击拨号DialpadFragment的onClick方法会被调用 public void onClick(View view) { int resId = view. ...
- jQuery 源码分析和使用心得 - 关于源码
说到jQuery, 大家可能直觉的认为jQuery的源码应该就是一个jquery.xx.js这样的一个文件. 但是看到真正的源码的时候, 整个人都思密达了.jQuery的源码做的事远比你想象的多, 为 ...
- Flink 源码解析 —— Standalone Session Cluster 启动流程深度分析之 Job Manager 启动
Job Manager 启动 https://t.zsxq.com/AurR3rN 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac ...
- Flink 源码解析 —— Standalone Session Cluster 启动流程深度分析之 Task Manager 启动
Task Manager 启动 https://t.zsxq.com/qjEUFau 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Ma ...
- Tomcat源码分析一:编译Tomcat源码
Tomcat源码分析一:编译Tomcat源码 1 内容介绍 在之前的<Servlet与Tomcat运行示例>一文中,给大家带来如何在Tomcat中部署Servlet应用的相关步骤,本文将就 ...
- Android源码分析(十一)-----Android源码中如何引用aar文件
一:aar文件如何引用 系统Settings中引用bidehelper-1.1.12.aar 文件为例 源码地址:packages/apps/Settings/Android.mk LOCAL_PAT ...
- Android源码分析(四)-----Android源码编译及刷机步骤
一 : 获取源码: 每个公司服务器地址不同,以如下源码地址为例: http://10.1.14.6/android/Qualcomm/msm89xx/branches/msm89xx svn环境执行: ...
- linux2.4.0源码下载地址(配合毛德操情景分析)
https://www.kernel.org/pub/linux/kernel/v2.4/
随机推荐
- Source Insight 中使用 AStyle 代码格式工具
Source Insight 中使用 AStyle 代码格式工具 彭会锋 2015-05-19 23:26:32 Source Insight是较好的代码阅读和编辑工具,不过source in ...
- mysql查询优化(持续更新中)
1. 索引不会包含有NULL值的列 (1) 应尽量避免在where子句中对字段进行null值判断,否则将导致引擎放弃使用索引而进行全表扫描 (2) 数据库设计时不要让字段的默认值 ...
- \bin\sh.exe:*** Couldn't reserve space for cygwin's heap,Win32 error 0
Git一直使用都好好的,今天git pull的时候,报了如下的错误,\bin\sh.exe:*** Couldn't reserve space for cygwin's heap,Win32 err ...
- go——搭建Win7下的Go开发环境
1.首先需要下载下载go平台安装包 安装程序 下载地址:https://golang.org/dl/ (墙内下载地址http://www.golangtc.com/download),如果是您的系统是 ...
- Windows Store App 用户库文件操作
(1)获取用户库位置 如果想要通过应用程序在用户库中创建文件,首先需要获得用户库中指定的位置,例如图片库.文档库等.这里值得注意的是,在获取用户库的位置之前,必须在Windows应用商店项目的清单文件 ...
- 在eclipse导入项目的步骤【转】
1. Import 2. Next 3. 确定 选中copy projects into workspace Finish 这样项目就导入进来了. 4.导入jar包 Configure Bui ...
- 使用HTTP访问网络------使用HTTPURLConnection
HTTPURLConnection继承了URLConnection,因此也可用于向指定网站发送GET请求.POST请求.它在URLConnection的基础上提供了如下便捷的方法: 1.int ge ...
- 在Android应用中使用OpenGL
Android为OpenGL ES支持提供了GLSurfaceView组件,这个组件用于显示3D图形.GLSurfaceView本身并不提供绘制3D图形的功能,而是由GLSurfaceView.Re ...
- js里面引入js
document.write('<script src="http://js.xcar.com.cn/bbs/sidebar/js/publicSidebar.js"> ...
- 二模 (7) day1
第一题: 题目大意: 给出数轴上N棵树的坐标和高度,如果两棵树之间的距离小于其中一颗树的高度,那么就有树会被挡住.因此要把一些树砍矮一点.求砍树的总高度最小值. N<=100000; 解题过程: ...