日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STL中sort算法简析

發(fā)布時(shí)間:2024/4/11 编程问答 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STL中sort算法简析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

STL里sort算法簡析

文章目錄

  • STL里sort算法簡析
    • 一、引入
    • 二、正解
    • 三、源碼
      • **`sort的源碼`**:
      • **`其中,__introsort_loop便是內(nèi)省式排序:`**
      • 插入排序
      • **快速排序?qū)崿F(xiàn)代碼**
      • 函數(shù)__lg()防止棧溢出

一、引入

如果面試官給你出了一道面試題:STL里sort算法用的是什么排序算法?

  • 當(dāng)你第一眼看到這道面試題是不是心里在暗喜,因?yàn)榕判蛑v的是效率,時(shí)間復(fù)雜度越小越好,并且作為STL的標(biāo)準(zhǔn)算法,更因該注重效率,這時(shí)你的腦海里想的肯定是快排
  • 此時(shí)如果你回答:
  • STL里的sort算法肯定用的是快速排序啊?難不成還是冒泡排序么?那么恭喜你,你可能錯(cuò)失了大廠的機(jī)會(huì),如果面試官不提醒你,你可能覺得自己面的還可以
  • 嘿嘿😁~~~

如果你回答的是快排并且面試官?zèng)]有放棄你的話,你可能會(huì)遇到如下問題:

  • 數(shù)據(jù)量大和數(shù)據(jù)量小都適合用快速排序嗎?
  • 快速排序的時(shí)間復(fù)雜度不是穩(wěn)定的nlogn,最壞情況會(huì)變成n^2,怎么解決復(fù)雜度惡化問題?
  • 快速排序遞歸實(shí)現(xiàn)時(shí),怎么解決遞歸層次過深的問題?
  • 遞歸過深會(huì)引發(fā)什么問題?
  • 怎么控制遞歸深度?如果達(dá)到遞歸深度了還沒排完序怎么辦?

如果面試官問你了,那么說明你的大廠offer正在向你靠近,因?yàn)檫@些問題并不是你不會(huì),只不過是沒沒把重心放在那方面而已

二、正解

  • 1.sort函數(shù)提供了兩個(gè)版本
  • sort(first, last):默認(rèn)按照小于方式排序,排序結(jié)果為升序,一般用排內(nèi)置類型數(shù)據(jù)
  • sort(first, last, comp):可以通過comp更改元素比較方式,即可以指定排序的結(jié)果為升序或者降序,一般以仿函數(shù)對象和函數(shù)指針的方式提供
  • 2.sort并不是一種排序算法,而是將多個(gè)排序算法混合而成
  • 3. 當(dāng)元素個(gè)數(shù)少于__stl_threshold閾值時(shí)(16),使用直接插入排序處理
  • 4. 當(dāng)元素個(gè)數(shù)超過__stl_threshold時(shí),考慮是否能用快排的方式排序,因?yàn)楫?dāng)元素?cái)?shù)量達(dá)到一定程度,遞歸式的快排可能會(huì)導(dǎo)致棧溢出而崩,因此:
  • 通過__lg函數(shù)判斷遞歸的深度
  • 5.如果遞歸的深度沒有超過2*lg(n) 時(shí),則使用快排方式排序,注意:快排時(shí)使用到了三數(shù)取中法預(yù)防分割后一邊沒有數(shù)據(jù)的極端情況
  • 如果遞歸深度超過2*lg(n) 時(shí),說明數(shù)據(jù)量大,遞歸層次太深,可能會(huì)導(dǎo)致棧溢出,此時(shí)使用堆排序處理

是不是很驚喜,很意外?

為什么?直接看STL源碼實(shí)現(xiàn),來源于侯捷老師翻譯的鼎鼎大名的 《STL源碼剖析》 關(guān)于sort算法實(shí)現(xiàn)的細(xì)節(jié),實(shí)現(xiàn)細(xì)節(jié)有很多精彩的地方。

總結(jié):sort算法用到了快速排序,但不僅僅只用了快速排序,還結(jié)合了插入排序和堆排序。

三、源碼

sort的源碼

template<typename _RandomAccessIterator>inline void sort(_RandomAccessIterator __first, _RandomAccessIterator __last){typedef typename iterator_traits<_RandomAccessIterator>::value_type_ValueType;// concept requirements__glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<_RandomAccessIterator>)__glibcxx_function_requires(_LessThanComparableConcept<_ValueType>)__glibcxx_requires_valid_range(__first, __last);if (__first != __last){//快速排序+插入排序std::__introsort_loop(__first, __last,std::__lg(__last - __first) * 2);//插入排序std::__final_insertion_sort(__first, __last);}}

其中,__introsort_loop便是內(nèi)省式排序:

template <class _RandomAccessIter, class _Tp, class _Size>void __introsort_loop(_RandomAccessIter __first,_RandomAccessIter __last, _Tp*,_Size __depth_limit) {while (__last - __first > __stl_threshold) {if (__depth_limit == 0) {partial_sort(__first, __last, __last);return;}--__depth_limit;_RandomAccessIter __cut =__unguarded_partition(__first, __last, _Tp(__median(*__first,*(__first + (__last - __first) / 2),*(__last - 1))));__introsort_loop(__cut, __last, (_Tp*)0, __depth_limit);__last = __cut;}}
  • 這里進(jìn)來之后會(huì) 首先進(jìn)行判斷元素是否大于__stl_threshold, __stl_threshold是一個(gè)常量值是16,意思就是說我傳入的元素規(guī)模小于我們的16的時(shí)候我們就沒必要采用我們的內(nèi)省式算法,直接退回去采用我們的插入排序。
  • 這里能看到我們的內(nèi)省式算法結(jié)束之后就是我們的插入排序函數(shù)。

插入排序

template<typename _RandomAccessIterator>void__final_insertion_sort(_RandomAccessIterator __first,_RandomAccessIterator __last){if (__last - __first > int(_S_threshold)){//先排前16個(gè)std::__insertion_sort(__first, __first + int(_S_threshold));//后面元素遍歷插入到前面有序的正確位置 std::__unguarded_insertion_sort(__first + int(_S_threshold), __last);}elsestd::__insertion_sort(__first, __last);}
  • 如果說我們的 元素規(guī)模大于我們的16了,那就需要去判斷如果我們是不是能采用快速排序,怎么判斷呢?快排是使用遞歸來實(shí)現(xiàn)的,如果說我們進(jìn)行判斷我們的遞歸深度沒有到達(dá)我們的最深層次上邊的函數(shù)已經(jīng)看過了,最深是2*lg(n)。那我們就去使用我們的快速排序來進(jìn)行排序

快速排序?qū)崿F(xiàn)代碼

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;} }
  • 如果說大于我們的最深層次的話,這里就會(huì)采用我們的堆排序,進(jìn)行排序。
  • 當(dāng)進(jìn)行完這個(gè)過程的時(shí)候要明白,這里并不是說整個(gè)傳進(jìn)來的數(shù)組都是這個(gè)過程,這里我們是進(jìn)行的一次排序,他可能是我傳入的數(shù)組,也可能是我在進(jìn)行快排分割之后的左半部分,排序結(jié)束之后再去排我的右半部分,所以可以看上邊我們的元素規(guī)模是不是大于__stl_threshold這個(gè)閾值的時(shí)候是一個(gè)while循環(huán)。

函數(shù)__lg()防止棧溢出

其第三個(gè)參數(shù)中所調(diào)用的函數(shù)__lg()便是用來控制分割惡化情況。代碼如下

template <class Size>inline Size __lg(Size n) {Size k;for (k = 0; n > 1; n >>= 1) ++k;return k;}

總結(jié)

以上是生活随笔為你收集整理的STL中sort算法简析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。