快速选择(quick_select) 算法分析
2014-05-09 15:48
507 查看
快速选择算法,就是从给定的一个集合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
如果使用排序,比如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 Algorithm 快速选择算法
- 快速选择(QuickSelect)的平均时间复杂度分析
- 快速排序与快速选择算法(quick sort and quick select algorithm)
- 冒泡排序、选择排序、堆排序、快速排序、插入排序算法复杂度分析与算法实现(自己总结与转)
- 算法分析之——quick-sort快速排序
- 笔试算法题(56):快速排序实现之非递归实现,最小k值选择(non-recursive version, Minimal Kth Selection of Quick Sort)
- 冒泡排序、选择排序、堆排序、快速排序、插入排序算法复杂度分析与算法实现(自己总结与转)
- 快速选择(quick select) + 线性时间选择(linear-time select) - 求出n个数中第k大的数
- 算法分析中最常用的几种排序算法(插入排序、希尔排序、冒泡排序、选择排序、快速排序,归并排序)C 语言版
- 快速选择(quick select) + 线性时间选择(linear-time select) - 求出n个数中第k大的数
- 算法分析之冒泡,快速,选择排序
- 【数据结构笔记】快速排序(quick_sort)和快速选择(quick_select)--Python2.7
- 算法分析:快速选择
- 读书笔记:"算法导论"之RANDOMIZED-SELECT(快速选择算法)
- leetcode:Kth Largest Element in an Array 使用快速选择算法,以及对其复杂度的分析
- 快速选择排序(quickselect)--基于quicksort
- 插入快速混合排序法分析(算法导论7.4-5解答)
- 【快速选择算法与nth_element函数】【续UVA11300 】
- 十四、第三章再续:快速选择SELECT算法的深入分析与实现
- 算法--数组冒泡排序和选择排序原理分析