快速选择(quick_select) 算法分析

快速选择算法,就是从给定的一个集合S={a1,a2,...an}中选出第K个大小的数,或者给出其所在的下标之类的。

如果使用排序,比如merge_sort,然后返回第K个元素的下标,复杂度是O(NlogN)

如果使用heap_sort,或者优先队列,则复杂度是O(NlogK)

如果使用quick _sort的一个变种,叫 quick select,则平均复杂度为O(N),最坏复杂度为O(N^2)

如果使用一种线性选择算法,则可以达到最坏O(N)的复杂度,不过实际应用中,该算法通常比quick select慢1到2倍,所以并不常用(参考Blum, Floyd, Pratt, Rivest, and Tarjan 1973  Time bounds for selection)

算法思想:

(1)利用快速排序的分治思想,求得待搜索数组按照的主元S[q](pivot)(主元的选定有好几种方法,这里不详细讨论,可参考快速排序),以主元为界分成左右两个区间

(2)通过比较主元的位置,判断第K个大小的数在主元左区间?在主元又区间?还是就是主元?(还要注意边界条件的判断,有可能在边界)

(3)进入子区间递归调用

这里实现了stl风格的quick select,仅仅作为一个mark

#include <algorithm>
#include <cassert>
namespace algorithm
{
template<typename _Tp>
const _Tp& choose_pivot(const _Tp& x, const _Tp& y, const _Tp& z)
{
        if( (x < y && y < z)||(z < y && y < x) )
                return y;
        else if( (z < x && x < y)||(y < x && x < z) )
                return x;
        else
                return z;
}
template<typename _Tp,typename _Compare>
const _Tp& choose_pivot(const _Tp& x, const _Tp& y,const _Tp& z, _Compare comp)
{
        if( (comp(x,y) && comp(y,z))||(comp(z,y)&&comp(y,x)) )
                return y;
        else if( (comp(z,x) && comp(x,y))||(comp(y,x)&&comp(x,z)))
                return x;
        return z;
}
template<typename _RandomAccessIterator,typename _Tp>
_RandomAccessIterator quick_partition(_RandomAccessIterator first,
                _RandomAccessIterator last,_Tp pivot)
{
        while( true ){
                while( *first < pivot )
                        ++first;
                --last;
                while( pivot < *last )
                        --last;
                if( first >= last )
                        return first;
                std::swap(*first,*last);
                ++first;
        }
}
template<typename _RandomAccessIterator,typename _Tp, typename _Compare>
_RandomAccessIterator quick_partition(_RandomAccessIterator first,
        _RandomAccessIterator last, _Tp pivot, _Compare comp)
{
        while( true ){
                while( comp(*first,pivot) == true )
                        ++first;
                --last;
                while( comp(pivot,*last) == true )
                        --last;
                if( first >= last )
                        return first;
                std::swap(*first,*last);
                ++first;
        }
}

template<typename _RandomAccessIterator>
_RandomAccessIterator quick_select(_RandomAccessIterator first, _RandomAccessIterator last, size_t kth)
{
        typedef typename std::iterator_traits<_RandomAccessIterator>::value_type _ValueType;
        typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type _DistanceType;
        if( first == last || last-first <=(_DistanceType)kth )//out of range
                return last;
        _ValueType pivot;
        _RandomAccessIterator mid;
        while( true )
        {
                if( kth == 0 )
                        return std::min_element(first,last);
                else if( first+kth == last - 1 )
                        return std::max_element(first,last);
                else{
                        mid = first+(last-first)/2;
                        pivot = choose_pivot(*first,*mid,*(last-1));
                        mid = quick_partition(first,last,pivot);
                        if( mid-first > (_DistanceType)kth )
                                last = mid;
                        else{
                                kth -= mid-first;
                                first = mid;
                        }
                }
                assert( last-first > (_DistanceType)kth);
        }
}

template<typename _RandomAccessIterator,typename _Compare>
_RandomAccessIterator quick_select(_RandomAccessIterator first, _RandomAccessIterator last, size_t kth,_Compare comp)
{
        typedef typename std::iterator_traits<_RandomAccessIterator>::value_type _ValueType;
        typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type _DistanceType;
        if( first == last || last-first <=(_DistanceType)kth )//out of range
                return last;
        _ValueType pivot;
        _RandomAccessIterator mid;
        while( true )
        {
                if( kth == 0 )
                        return std::min_element(first,last,comp);
                else if( first+kth == last - 1 )
                        return std::max_element(first,last,comp);
                else{
                        mid = first+(last-first)/2;
                        pivot = choose_pivot(*first,*mid,*(last-1),comp);
                        mid = quick_partition(first,last,pivot,comp);
                        if( mid-first > (_DistanceType)kth )
                                last = mid;
                        else{
                                kth -= mid-first;
                                first = mid;
                        }
                }
                assert( last-first > (_DistanceType)kth);
        }
}
} //namespace

快速选择(quick_select) 算法分析,布布扣,bubuko.com

时间: 2024-11-10 17:30:43

快速选择(quick_select) 算法分析的相关文章

求一无序数组中第n大的数字 - 快速选择算法

逛别人博客的时候,偶然看到这一算法题,顺便用C++实现了一下. 最朴素的解法就是先对数组进行排序,返回第n个数即可.. 下面代码中用的是快速选择算法(不晓得这名字对不对) 1 #include <vector> 2 #include <iostream> 3 #include <stdexcept> 4 #include <cstdio> 5 6 const int QS_EERRMSG_LEN = 256; 7 8 9 /** 10 * 快速选择求无序数组

算法分析的正确姿势

[本系列博文会对常见的数据结构及相应算法进行分析与总结,并会在每篇博文中提供几道相关的一线互联网企业面试/笔试题来巩固所学及帮助我们查漏补缺.项目地址:https://github.com/absfree/Algo.由于个人水平有限,叙述中难免存在不清晰准确的地方,希望大家可以指正,谢谢大家:)] 一.前言 在进一步学习数据结构与算法前,我们应该先掌握算法分析的一般方法.算法分析主要包括对算法的时空复杂度进行分析,但有些时候我们更关心算法的实际运行性能如何,此外,算法可视化是一项帮助我们理解算法

JavaScript插件:快速选择日期----jedate日历插件

jedate是一款轻量级JS库,可快速选择日期 http://www.sucaijiayuan.com/Js/DateTime/1371.html 使用方法: 下载jedate , 解压后不要改变文件夹内的目录结构,然后引入jedate.js文件, <input id="datepicker" placeholder="请选择时间" type="text" readonly/> var datepickerOptions = { da

算法分析与设计复习

算法分析与设计复习 2016年初,研一上学期期末考试前,复习并总结算法分析与设计科目的内容.复习过程参照<算法导论>中文第2版,同时参照PPT,章节划分根据PPT内容 概要: 第一章 概述 第二章 插入排序&分治策略 第三章 复杂度分析 第四章 堆与堆排序 第五章 快速排序 第六章 线性时间排序 第一章 概述 算法的应用范围 算法在诸如生物等诸多领域有其应用 算法的意义 算法在很多情况下让不可能完成的事情变成了可能,让处理的很慢的过程变快. 一个铺垫 一串不全为0的数,怎么取能拿到一段

拓扑排序之变量序列算法分析

拓扑排序之变量序列 巧若拙(欢迎转载,但请注明出处:http://blog.csdn.net/qiaoruozhuo) 题目描述: 假设有n个变量(1<=n<=26,变量名用单个小写字母表示),还有m个二元组(u,v),分别表示变量u小于v.那么,所有变量从小到大排列起来应该是什么样子的呢? 例如有4个变量a,b,c,d,若以知a<b,c<b,d<c,则这4个变量的排序可能是a<d<c<b.尽管还有可能其他的可能,你只需找出其中的一个即可. 输入: 输入为一

ux.form.field.GridDate 支持快速选择日期的日期控件

效果如图,亲测6.2.1版本可用 1 /** 2 *支持快速选择日期的日期控件 3 */ 4 Ext.define('ux.form.field.GridDate', { 5 extend: 'Ext.form.field.Date', 6 alias: 'widget.gridDateField', 7 requires: ['ux.picker.GridDate'], 8 pickerGrid: { 9 store: { 10 //默认配置 11 data: [{ 12 value: 30,

某某水表-M1卡数据算法分析

# 某某水表-M1卡数据算法分析 ## 卡片数据-----------------------------扇区数据 | 金额:--- |:---13EC 0000 0000 0000 0000 0000 03EB BD1B | 51.0013E7 0000 0000 0000 0000 0000 03F0 AD2B | 50.9513E2 0000 0000 0000 0000 0000 03F5 AD2B | 50.8513DD 0000 0000 0000 0000 0000 03FA 9D

算法分析

算法就是一系列解决问题的指令,对于给定的输入,能够在有限时间内获得预期的输出.一个好的算法和一篇好的文章一样,都是不断努力,反复修正的结果.算法分析主要从运行时间和存储空间两方面讨论算法的效率.相信有些人会有跟我一样的感觉,对于一些算法,有时我们一眼就能看出它的时间复杂度,但就是无法比较规范的表达出来.本文就系统的整理一下如何规范推导算法的时间和空间复杂度. 算法分析的一个依据是,输入规模(又称问题规模,记为 n),根据直觉,程序的运行时间随着问题规模的增大而变长.那么怎么衡量程序的运行时间呢?

[MD5变形算法练习] AutoRun Design Specialty算法分析

[破文标题][MD5变形算法练习] AutoRun Design Specialty算法分析[破文作者]静心学习[作者邮箱][email protected][作者主页]http://www.cnblogs.com/dacainiao/[破解工具]OD, DEDE, IDA[破解平台]xp sp3[软件名称]AutoRun Design Specialty[软件大小]6.98MB[原版下载]http://www.alleysoft.com/autorundesignspecialty/ARDSS