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/
随机推荐
- [接口服务] Jersey Rest Demo
http://files.cnblogs.com/files/avivaye/RestProject.rar
- 数据库中User和Schema的关系
如果我们想了解数据库中的User和Schema到底什么关系,那么让我们首先来了解一下数据库中User和Schema到底是什么概念. 在SQL Server2000中,由于架构的原因,Us ...
- WPF:ListView数据绑定及Style
DrugRecordsWin.xaml <ListView Grid.Row="4" Grid.Column="1" Name="list_Dr ...
- hdu----(1402)A * B Problem Plus(FFT模板)
A * B Problem Plus Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- linux在shell date获取时间的相关操作
获得当天的日期 date +%Y-%m-%d 输出: 2011-07-28 将当前日期赋值给DATE变量DATE=$(date +%Y%m%d) 有时候我们需要使用今天之前或者往后的日期,这时可以使用 ...
- FZU 1911 Construct a Matrix
题目链接:Construct a Matrix 题意:构造一个矩阵,要求矩阵的每行每列的和都不相同.矩阵的边长是前n项斐波那契的和. 思路:由sn = 2*(fn-1)+(fn-2)-1,只要知道第n ...
- sp转dp dp转px
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mTextSize, context.getResources().getDis ...
- 使用AlarmManager定时更换壁纸----之一
import android.os.Bundle;import android.app.Activity;import android.app.AlarmManager;import android. ...
- C#中三种定时器对象的比较
·关于C#中timer类 在C#里关于定时器类就有3个1.定义在System.Windows.Forms里2.定义在System.Threading.Timer类里3.定义在System.Timers ...
- S1:原型继承
一.基本性质 function obj(){ this.name1 = '可以被delete删除'; } obj.prototype.name2 = '不能被delete删除'; obj.protot ...