= __last) { //只有一个记录 ,不需要排序 __introsort_loop(__first, __last, __VALUE_TYPE(__first first, __last); //剩下未排序的数据,直接插入排序 } }template <class _RandomAccessIter, class _Tp, class _Size>void __introsort_loop last - __first)/2), *(__last - 1))));////找三个位置的中位数作为快排依据 __introsort_loop last, (_Tp*) 0, __depth_limit); //排后一部分 __last = __cut; //排前一部分 } } std:sort描述 维基百科 内省排序 内省排序(英语:Introsort
二、自省排序(内观排序) 自省排序(Introsort)是一种混合排序算法,它结合了快速排序(Quicksort)、堆排序(Heapsort)和插入排序(Insertion sort)的优点。 introsort的快排排序OJ代码 ——C++库提出来的 1、找基准值出现问题 这里的introsort是introspective(自省的) sort采用了缩写,他的名字其实表达了他的实现思路,他的思路就是进行自我侦测和反省 2、代码实现 代码演示: //自省排序(内观排序) void IntroSort(int* arr, int left, int right, int depth, int defaultDepth) } ++cur; } Swap(&arr[prev], &arr[keyi]); keyi = prev; //[begin,keyi-1] keyi [keyi+1,end] IntroSort (a, begin, keyi - 1, depth, defaultDepth); IntroSort(a, keyi + 1, end, depth, defaultDepth);
= __last) { __introsort_loop(__first, __last, __VALUE_TYPE(__first), if语句先判断区间有效性,接着调用__introsort_loop,它就是STL的Introspective Sort(内省式排序)实现。在该函数结束之后,最后调用插入排序。 __introsort_loop template <class _RandomAccessIter, class _Tp, class _Size, class _Compare> void __introsort_loop 为: template <class _RandomAccessIter, class _Tp, class _Size, class _Compare> void __introsort_loop 参考《STL 源码剖析》的图示: 分割图示例一 分割图示例二 __introsort_loop总结 1、在__introsort_loop函数中,首先会判断数据量大小,即如果last - first
它是一个int类型的depthLimit参数,这里简单点理解就是算出数组的深度,因为后边会根据这个值进行递归操作,然后进入到 IntroSort 方法。 IntroSort 到这个方法这里就清晰很多了, 这是Array.Sort<T> 排序的主要内容,接着往下看 https://source.dot.net/#System.Private.CoreLib /ArraySortHelper.cs,404 private static void IntroSort(Span<T> keys, int depthLimit) { Debug.Assert IntroSort(keys[(p+1)..partitionSize], depthLimit); partitionSize = p; } } 第一次进入方法时,partitionSize QuickSort int p = PickPivotAndPartition(keys.Slice(0, partitionSize), values.Slice(0, partitionSize)); IntroSort
冒泡排序和直接插入排序除外除外,我个人觉得这两个排序算法除了有一些教学价值基本0作用 二、内省排序(优秀的工业级排序) introsort是由David Musser在1997年设计的排序算法,C++sgi introsort是introspective sort采用了缩写,他的名字其实表达了他的实现思路,他的思路就是进行自我侦测和反省,快排递归深度太深(sgi STL中使用的是深度为2倍排序元素数量的对数值 } Swap(&a[prev], &a[keyi]); keyi = prev; // [begin, keyi-1] keyi [keyi+1, end] IntroSort (a, begin, keyi - 1, depth, defaultDepth); IntroSort(a, keyi + 1, end, depth, defaultDepth); } void 1; for (int i = 1; i < N; i *= 2) { logn++; } // introspective sort -- ⾃省排序 IntroSort
自省排序 introsort是由David Musser在1997年设计的排序算法,C++ sgi STLsort中就是用的introspectivesort(内省排序)思想实现的。 代码:(堆排序与插入排序不再赘述) void IntroSort(int* a, int left, int right, int depth, int defaultDepth) { if (left ); } ++cur; } Swap(&a[prev], &a[keyi]); keyi = prev; // [begin, keyi-1] keyi [keyi+1, end] IntroSort (a, begin, keyi - 1, depth, defaultDepth); IntroSort(a, keyi + 1, end, depth, defaultDepth); } void left + 1; //计算logn for (int i = 1; i < N; i *= 2) { logn++; } // introspective sort -- 自省排序 IntroSort
sort总体概览 前面介绍了内省式排序,所以看下sort是怎么一步步来使用introsort的,上一段入口代码: template <class RandomAccessIterator> inline = last) { __introsort_loop(first, last, value_type(first), __lg(last - first) * 2); _ _final_insertion_sort(first, last); } } 从代码来看sort使用了first和last两个随机存取迭代器,作为待排序序列的开始和终止,进一步调用了__introsort_loop 其中注意到__introsort_loop的第三个参数__lg(last - first)*2,凭借我们的经验来猜(蒙)一下吧,应该递归深度的限制,不急看下代码实现: template <class Size 快速排序和堆排序的配合 __introsort_loop函数中主要封装了快速排序和堆排序,来看看这个函数的实现细节: //sort函数的入口 template <class RandomAccessIterator
#include"introsort.h" void Swap(int* x, int* y) { int tmp = *x; *x = *y; *y = tmp; } void AdjustDown ); // 使用中间值作为基准值,并将其移到 left 位置 Swap(&arr[left], &arr[mid]); return arr[left]; // 返回基准值 } void IntroSort ); } ++cur; } Swap(&a[prev], &a[keyi]); keyi = prev; // [begin, keyi-1] keyi [keyi+1, end] IntroSort (a, begin, keyi - 1, depth, defaultDepth); IntroSort(a, keyi + 1, end, depth, defaultDepth); } void right - left + 1; for (int i = 1; i < N; i *= 2) { logn++; } // introspective sort -- ⾃省排序 IntroSort
而且非稳定的排序算法,IntroSort就已经很优秀了。 基本的优化思路还是以IntroSort为范本,对快速排序进行优化。 快速排序本身效率很高,但是大致有如下问题: 在 right – left 较小时,递归调用较多,操作效率低 枢轴选择不当时,最差会退化至 O(n^2) 处理大量重复数据时,枢轴选择容易不当 递归操作本身效率低下 而按照IntroSort 基本上与std::sort实现的IntroSort保持一致。由于每一个组成的算法都是稳定的,因此最终的排序算法也是稳定的。
= __last) 05219 { 05220 std::__introsort_loop(__first, __last, 05221 std::_ routine. 02243 template<typename _RandomAccessIterator, typename _Size> 02244 void 02245 __introsort_loop *(__last 02268 - 1)))); 02269 std::__introsort_loop
= __last) 05219 { 05220 std::__introsort_loop(__first, __last, 05221 std::_ routine. 02243 template<typename _RandomAccessIterator, typename _Size> 02244 void 02245 __introsort_loop *(__last 02268 - 1)))); 02269 std::__introsort_loop
现在可以过,leetcode哪天增加⼀个特殊测试⽤例以后,就过不了,三路划分也类似,因为他们的思想还是在特殊场景下效率会退化,⽐如⼤多数选key都是接近最⼩或者最⼤的值,导致划分不均衡,效率退化. 1️⃣introsort )); QuickSort(nums, 0, numsSize-1); *returnSize = numsSize; return nums; } 运行结果: 这是思路: 2.4introsort 的快速排序跑排序数组OJ题 introsort是introspective sort采⽤了缩写,他的名字其实表达了他的实现思路,他的思路就是进⾏⾃ 我侦测和反省,快排递归深度太深(sgi stl中使 (a, begin, keyi - 1, depth, defaultDepth); IntroSort(a, keyi+1, end, depth, defaultDepth); } void QuickSort int N = right-left+1; for(int i = 1; i < N; i *= 2) { logn++; } // introspective sort -- ⾃省排序 IntroSort
这里对上表其中几个效率相对较高的做个简要介绍,后面如有机会在深入学习总结: Introsort内省排序,在C++ STL中有应用。 内省排序(英语:Introsort)是由David Musser在1997年设计的排序算法。这个排序算法首先从快速排序开始,当递归深度超过一定深度(深度为排序元素数量的对数值)后转为堆排序。 事实上,在实际应用中有更复杂的变体,例如在Android,Java和Python中使用的Timsort(合并排序,插入排序和其他逻辑),以及在某些C++中用的introsort(快速排序和堆排序) 在.
内省排序(Introsort,也称内省式排序 introspective sort):是一种结合了快速排序、堆排序和插入排序优势的 混合排序算法 主要用于解决快速排序在最坏情况下时间复杂度退化到 #include "IntroSort.h" /*----------------------------------工具函数----------------------------------*/ (a, left, key - 1, depth, defaultDepth); IntroSort(a, key + 1, right, depth, defaultDepth); } /*- 当递归深度超过2*logN时,说明分区极度不平衡 * 此时切换为堆排序更安全 */ } 测试文件:Test.c #include "IntroSort.h" /*------------- (a, left, key - 1, depth, defaultDepth); IntroSort(a, key + 1, right, depth, defaultDepth); } /*-
ArrayList<DiscoveryNode> sortedNodes = CollectionUtils.iterableAsArrayList(nodes); CollectionUtil.introSort node.isMasterNode()); CollectionUtil.introSort(possibleNodes, ElectMasterService::compareNodes
ArrayList<DiscoveryNode> sortedNodes = CollectionUtils.iterableAsArrayList(nodes); CollectionUtil.introSort node.isMasterNode()); CollectionUtil.introSort(possibleNodes, ElectMasterService::compareNodes
不过需要注意的是这个排序算法的使用和对这些参数名字的期待会有所不同,比如传递kind=quicksort实际上采用的是一个 introsort 算法,这里给出 numpy 的文档解释: 当没有足够的进展的时候 默认对单列的排序算法是采用 Numpy 的 quicksort ,当然实际上调用的排序算法是 introsort ,因为堆排序会比较慢。 wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server 其他的 SQL 数据库采用不同的排序算法,比如根据下面这个回答,谷歌的 BigQuery 通过一些技巧实现 introsort docs.scipy.org/doc/numpy-1.16.0/reference/generated/numpy.sort.html#numpy.sort https://en.wikipedia.org/wiki/Introsort
未表现出比以前的其它算法慢 常见模式中pdqsort通常更快(即在排序切片中快10倍) pdqsort实质为一种混合排序算法,在不同情况下切换到不同的排序机制,该实现灵感来自C++和RUST的实现,是对C++标准库算法introsort
前面介绍了内省式排序,所以看下sort是怎么一步步来使用introsort的,上一段入口代码: ? 从代码来看sort使用了first和last两个随机存取迭代器,作为待排序序列的开始和终止,进一步调用了__introsort_loop和__final_insertion_sort两个函数,从字面上看前者是内省排序循环 其中注意到__introsort_loop的第三个参数__lg(last - first)*2,凭借我们的经验来猜(蒙)一下吧,应该递归深度的限制,不急看下代码实现: ? 快速排序和堆排序的配合 __introsort_loop函数中主要封装了快速排序和堆排序,来看看这个函数的实现细节: ? 各位先不要晕更不要蒙圈,一点点分析肯定可以拿下的。 last, Compare comp) { __partial_sort(first, middle, last, value_type(first), comp); } 插入排序上场了 __introsort_loop
Non-nan values are sorted as before.New in version 1.12.0.quicksort has been changed to introsort.