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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

编程问答

java.util.ComparableTimSort中的sort()方法简单分析

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

TimSort算法是一種起源于歸并排序和插入排序的混合排序算法,設(shè)計(jì)初衷是為了在真實(shí)世界中的各種數(shù)據(jù)中能夠有較好的性能。

該算法最初是由Tim Peters于2002年在Python語(yǔ)言中提出的。

TimSort 是一個(gè)歸并排序做了大量?jī)?yōu)化的版本號(hào)。

對(duì)歸并排序排在已經(jīng)反向排好序的輸入時(shí)表現(xiàn)O(n2)的特點(diǎn)做了特別優(yōu)化。對(duì)已經(jīng)正向排好序的輸入降低回溯。對(duì)兩種情況混合(一會(huì)升序。一會(huì)降序)的輸入處理比較好。

在jdk1.7之后。Arrays類中的sort方法有一個(gè)分支推斷,當(dāng)LegacyMergeSort.userRequested為true的情況下,採(cǎi)用legacyMergeSort,否則採(cǎi)用ComparableTimSort。而且在legacyMergeSort的凝視上標(biāo)明了該方法會(huì)在以后的jdk版本號(hào)中廢棄,因此以后Arrays類中的sort方法將採(cǎi)用ComparableTimSort類中的sort方法。

<span style="font-family:Microsoft YaHei;">public static void sort(Object[] a, int fromIndex, int toIndex) {if (LegacyMergeSort.userRequested)legacyMergeSort(a, fromIndex, toIndex);elseComparableTimSort.sort(a, fromIndex, toIndex); } </span>以下是ComparableTimSort的sort方法<span style="font-family:Microsoft YaHei;">static void sort(Object[] a) {sort(a, 0, a.length); }static void sort(Object[] a, int lo, int hi) {rangeCheck(a.length, lo, hi);int nRemaining = hi - lo;if (nRemaining < 2)return; // Arrays of size 0 and 1 are always sorted// If array is small, do a "mini-TimSort" with no mergesif (nRemaining < MIN_MERGE) {int initRunLen = countRunAndMakeAscending(a, lo, hi);binarySort(a, lo, hi, lo + initRunLen);return;}/*** March over the array once, left to right, finding natural runs,* extending short natural runs to minRun elements, and merging runs* to maintain stack invariant.*/ComparableTimSort ts = new ComparableTimSort(a);int minRun = minRunLength(nRemaining);do {// Identify next runint runLen = countRunAndMakeAscending(a, lo, hi);// If run is short, extend to min(minRun, nRemaining)if (runLen < minRun) {int force = nRemaining <= minRun ? nRemaining : minRun;binarySort(a, lo, lo + force, lo + runLen);runLen = force;}// Push run onto pending-run stack, and maybe mergets.pushRun(lo, runLen);ts.mergeCollapse();// Advance to find next runlo += runLen;nRemaining -= runLen;} while (nRemaining != 0);// Merge all remaining runs to complete sortassert lo == hi;ts.mergeForceCollapse();assert ts.stackSize == 1; }</span>(1)傳入的待排序數(shù)組若小于閾值MIN_MERGE(Java實(shí)現(xiàn)中為32。Python實(shí)現(xiàn)中為64)。則調(diào)用 binarySort,這是一個(gè)不包括合并操作的 mini-TimSort。

a) 從數(shù)組開(kāi)始處找到一組連接升序或嚴(yán)格降序(找到后翻轉(zhuǎn))的數(shù)
b) Binary Sort:使用二分查找的方法將興許的數(shù)插入之前的已排序數(shù)組。binarySort 對(duì)數(shù)組 a[lo:hi] 進(jìn)行排序,而且a[lo:start] 是已經(jīng)排好序的。算法的思路是對(duì)a[start:hi] 中的元素。每次使用binarySearch 為它在 a[lo:start] 中找到對(duì)應(yīng)位置,并插入。

(2)開(kāi)始真正的TimSort過(guò)程:

????? (2.1) 選取minRun大小,之后待排序數(shù)組將被分成以minRun大小為區(qū)塊的一塊塊子數(shù)組

a) 假設(shè)數(shù)組大小為2的N次冪,則返回16(MIN_MERGE / 2)
b) 其它情況下,逐位向右位移(即除以2),直到找到介于16和32間的一個(gè)數(shù)

  • minRun
<span style="font-family:Microsoft YaHei;">private static int minRunLength(int n) {assert n >= 0;int r = 0; // Becomes 1 if any 1 bits are shifted offwhile (n >= MIN_MERGE) {r |= (n & 1);n >>= 1;}return n + r;}</span>這個(gè)函數(shù)依據(jù) n 計(jì)算出相應(yīng)的 natural run 的最小長(zhǎng)度。

MIN_MERGE 默覺(jué)得32,假設(shè)n小于此值,那么返回n 本身。否則會(huì)將 n 不斷地右移。直到少于 MIN_MERGE,同一時(shí)候記錄一個(gè) r 值,r 代表最后一次移位n時(shí)。n最低位是0還是1。 最后返回 n + r,這也意味著僅僅保留最高的 5 位。再加上第六位。

(2.2)do-while

(2.2.1)找到初始的一組升序數(shù)列,countRunAndMakeAscending 會(huì)找到一個(gè)run 。這個(gè)run 必須是已經(jīng)排序的。而且函數(shù)會(huì)保證它為升序,也就是說(shuō),假設(shè)找到的是一個(gè)降序的。會(huì)對(duì)其進(jìn)行翻轉(zhuǎn)。

(2.2.2)若這組區(qū)塊大小小于minRun,則將興許的數(shù)補(bǔ)足,利用binarySort 對(duì) run 進(jìn)行擴(kuò)展。而且擴(kuò)展后,run 仍然是有序的。

(2.2.3)當(dāng)前的 run 位于 a[lo:runLen] ,將其入棧ts.pushRun(lo, runLen);//為興許merge各區(qū)塊作準(zhǔn)備:記錄當(dāng)前已排序的各區(qū)塊的大小

(2.2.4)對(duì)當(dāng)前的各區(qū)塊進(jìn)行merge,merge會(huì)滿足下面原則(如果X,Y,Z為相鄰的三個(gè)區(qū)塊):

a) 僅僅對(duì)相鄰的區(qū)塊merge
b) 若當(dāng)前區(qū)塊數(shù)僅為2,If X<=Y。將X和Y merge
b) 若當(dāng)前區(qū)塊數(shù)>=3,If X<=Y+Z。將X和Y merge。直到同一時(shí)候滿足X>Y+Z和Y>Z

因?yàn)橐喜⒌膬蓚€(gè) run 是已經(jīng)排序的,所以合并的時(shí)候,有會(huì)特別的技巧。如果兩個(gè) run 是 run1,run2 ,先用 gallopRight在 run1 里使用 binarySearch 查找run2 首元素 的位置k, 那么 run1 中 k 前面的元素就是合并后最小的那些元素。然后,在run2 中查找run1 尾元素 的位置 len2 ,那么run2 中 len2 后面的那些元素就是合并后最大的那些元素。最后,依據(jù)len1 與len2 大小。調(diào)用mergeLo 或者 mergeHi 將剩余元素合并。

(2.2.5) 反復(fù)2.2.1 ~ 2.2.4,直到將待排序數(shù)組排序完?
(2.2.6) Final Merge:假設(shè)此時(shí)還有區(qū)塊未merge,則合并它們

?(3)演示樣例

*注意*:為了演示方便,我將TimSort中的minRun直接設(shè)置為2,否則我不能用非常小的數(shù)組演示。。

。同一時(shí)候把MIN_MERGE也改成2(默覺(jué)得32),這樣避免直接進(jìn)入binary sort。

初始數(shù)組為[7,5,1,2,6,8,10,12,4,3,9,11,13,15,16,14]
=> 尋找連續(xù)的降序或升序序列 (2.2.1)。同一時(shí)候countRunAndMakeAscending 函數(shù)會(huì)保證它為升序
[1,5,7] [2,6,8,10,12,4,3,9,11,13,15,16,14]


=> 入棧 (2.2.3)
當(dāng)前的棧區(qū)塊為[3]

=> 進(jìn)入merge循環(huán) (2.2.4)
do not merge由于棧大小僅為1

=> 尋找連續(xù)的降序或升序序列 (2.2.1)
[1,5,7] [2,6,8,10,12] [4,3,9,11,13,15,16,14]

=> 入棧 (2.2.3)
當(dāng)前的棧區(qū)塊為[3, 5]

=> 進(jìn)入merge循環(huán) (2.2.4)
merge由于runLen[0]<=runLen[1]
1) gallopRight:尋找run1的第一個(gè)元素應(yīng)當(dāng)插入run0中哪個(gè)位置(”2”應(yīng)當(dāng)插入”1”之后),然后就能夠忽略之前run0的元素(都比run1的第一個(gè)元素小)
2) gallopLeft:尋找run0的最后一個(gè)元素應(yīng)當(dāng)插入run1中哪個(gè)位置(”7”應(yīng)當(dāng)插入”8”之前),然后就能夠忽略之后run1的元素(都比run0的最后一個(gè)元素大)
這樣須要排序的元素就僅剩下[5,7] [2,6],然后進(jìn)行mergeLow
完畢之后的結(jié)果:
[1,2,5,6,7,8,10,12] [4,3,9,11,13,15,16,14]

=> 入棧 (2.2.3)
當(dāng)前的棧區(qū)塊為[8]
退出當(dāng)前merge循環(huán)由于棧中的區(qū)塊僅為1

=> 尋找連續(xù)的降序或升序序列 (2.2.1)
[1,2,5,6,7,8,10,12] [3,4] [9,11,13,15,16,14]
=> 入棧 (2.2.3)
當(dāng)前的棧區(qū)塊大小為[8,2]


=> 進(jìn)入merge循環(huán) (2.2.4)
do not merge由于runLen[0]>runLen[1]


=> 尋找連續(xù)的降序或升序序列 (2.2.1)
[1,2,5,6,7,8,10,12] [3,4] [9,11,13,15,16] [14]


=> 入棧 (2.2.3)
當(dāng)前的棧區(qū)塊為[8,2,5]


=>
do not merege run1與run2由于不滿足runLen[0]<=runLen[1]+runLen[2]
merge run2與run3由于runLen[1]<=runLen[2]
1) gallopRight:發(fā)現(xiàn)run1和run2就已經(jīng)排好序
完畢之后的結(jié)果:
[1,2,5,6,7,8,10,12] [3,4,9,11,13,15,16] [14]


=> 入棧 (2.2.3)
當(dāng)前入棧的區(qū)塊大小為[8,7]
退出merge循環(huán)由于runLen[0]>runLen[1]


=> 尋找連續(xù)的降序或升序序列 (2.2.1)
最后僅僅剩下[14]這個(gè)元素:[1,2,5,6,7,8,10,12] [3,4,9,11,13,15,16] [14]


=> 入棧 (2.2.3)
當(dāng)前入棧的區(qū)塊大小為[8,7,1]


=> 進(jìn)入merge循環(huán) (2.2.4)
merge由于runLen[0]<=runLen[1]+runLen[2]
由于runLen[0]>runLen[2],所以將run1和run2先合并。(否則將run0和run1先合并)
1) gallopRight & 2) gallopLeft
這樣須要排序的元素剩下[13,15] [14],然后進(jìn)行mergeHigh
完畢之后的結(jié)果:
[1,2,5,6,7,8,10,12] [3,4,9,11,13,14,15,16] 當(dāng)前入棧的區(qū)塊為[8,8]


=>
繼續(xù)merge由于runLen[0]<=runLen[1]
1) gallopRight & 2) gallopLeft
須要排序的元素剩下[5,6,7,8,10,12] [3,4,9,11]。然后進(jìn)行mergeHigh
完畢之后的結(jié)果:
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16] 當(dāng)前入棧的區(qū)塊大小為[16]


=>
不須要final merge由于當(dāng)前棧大小為1


=>
結(jié)束


參考:

http://www.lifebackup.cn/timsort-java7.html

http://blog.csdn.net/on_1y/article/details/30109975

http://en.wikipedia.org/wiki/Timsort

轉(zhuǎn)載于:https://www.cnblogs.com/lxjshuju/p/7081959.html

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

以上是生活随笔為你收集整理的java.util.ComparableTimSort中的sort()方法简单分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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