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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

java什么是稳定排序,这可能是你听说过最快的稳定排序算法

發(fā)布時間:2025/3/20 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java什么是稳定排序,这可能是你听说过最快的稳定排序算法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

作者丨Brandon Skerritt

譯者丨阿拉丁

策劃丨蔡芳芳

知道 Java 和 Python 的默認(rèn)排序算法是什么嗎?這個算法叫作 Timsort,由 Tim Peters 與 2001 年創(chuàng)建,是一種穩(wěn)定高效的面向真實數(shù)據(jù)的排序算法。

Timsort 是一種面向真實數(shù)據(jù)的高效排序算法,它不是在學(xué)術(shù)實驗室中創(chuàng)建出來的。2001 年,Tim Peters 為 Python 創(chuàng)建了 Timsort 算法。Timsort 算法首先對排序數(shù)據(jù)進(jìn)行分析,然后根據(jù)分析結(jié)果來選擇排序方式。

在該算法出現(xiàn)之后,就一直被作為 Python、Java、Android 平臺和 GNU Octave 的默認(rèn)排序算法。

Timsort 的時間復(fù)雜度是 O(n log n)。關(guān)于時間復(fù)雜度,可以參考下圖。

Timsort 的排序時間與歸并排序相同。實際上,Timsort 使用了插入排序和歸并排序,你很快就會看到。

Timsort 利用了存在于大多數(shù)真實數(shù)據(jù)集中的已排序元素,這些已排序的元素被稱為“natural runs”。算法會遍歷要排序的數(shù)據(jù),將元素收集到 run 中,同時將這些 run 合并在一起。

元素個數(shù)少于 64 的數(shù)組

如果數(shù)組的元素個數(shù)少于 64,Timsort 將執(zhí)行插入排序。

插入排序是一種對小數(shù)據(jù)集最為有效的排序算法。它在排序較大的數(shù)據(jù)集時速度很慢,但在排序較小的數(shù)據(jù)集時速度很快。插入排序的思想如下:

逐個檢查元素;

在正確的位置插入正確的元素,以此來構(gòu)建排好序的列表。

在這個示例中,我們將新排序的元素插入到一個新的子數(shù)組中,從數(shù)組的頭部開始。

插入排序的 GIF 動畫演示:

關(guān)于 run

如果列表的元素個數(shù)大于 64,Timsort 會先遍歷列表,查找嚴(yán)格遞增或遞減的部分。如果這個部分是遞減的,就反轉(zhuǎn)這個部分。

所以,如果 run 是遞減的,它看起來像這樣(其中 run 使用粗體表示):

如果不是遞減的,它看起來是這樣的:

minrun 根據(jù)數(shù)組的大小來確定。當(dāng) run 的數(shù)量等于或略小于 2 的冪時,合并 2 個數(shù)組的效率會更高。為了確保效率,Timsort 選擇的 minrun 通常等于或小于 2 的冪。

minrun 的取值范圍為 32 到 64。原始數(shù)組的長度除以 minrun 仍然等于或略小于 2 的冪。

如果 run 的長度小于 minrun,就用 minrun 減去這個 run 的長度,得出一個數(shù)字,然后針對這個數(shù)字長度的元素執(zhí)行插入排序,以此來創(chuàng)建新的 run。

所以,如果 minrun 是 63,run 的長度是 33,那么就是 63-33=30,也就是對 run[33] 前的 30 個元素執(zhí)行插入排序來創(chuàng)建新的 run。

在這部分完成之后,我們就有了一系列排好序的 run。

合并

接下來,Timsort 會執(zhí)行歸并排序,將 run 合并在一起。Timsort 在執(zhí)行合并排序時會確保穩(wěn)定性和均衡性。

為了確保穩(wěn)定性,我們不需要交換兩個相等的數(shù)字。這樣不僅可以保持它們在列表中的原始位置不動,而且會讓算法更快。我們很快就會解釋合并的均衡性問題。

在遇到一個 run 時,Timsort 將它添加到棧中。一個簡單的??雌饋硐襁@樣:

你可以想象面前有一疊盤子,但你不能從底部拿盤子,必須從頂部拿。棧也是這個原理。

Timsort 在合并 run 時會嘗試平衡兩個相互矛盾的需求。一方面,我們希望盡可能多地推遲合并,以便找出可能會出現(xiàn)的模式,但也更希望盡快地進(jìn)行合并,以便利用剛剛發(fā)現(xiàn)的 run。但我們不能延遲合并“太久”,因為我們需要記住未合并的 run,而這樣做會消耗更多的內(nèi)存。

為了獲得這種平衡,Timsort 會跟蹤棧上最新的三個項,這些項必須遵循以下規(guī)則:

A > B + C

B > C

其中 A、B 和 C 是棧上最新的三個項。

通常,合并不同長度的相鄰的 run 是很困難的,而更困難的是我們必須確保穩(wěn)定性。為了解決這個問題,Timsort 會留出臨時內(nèi)存,將較小的 run 放到臨時內(nèi)存中。

“奔馳”模式

Timsort 在合并 run A 和 run B 時會發(fā)現(xiàn)其中一個 run 連續(xù)多次“獲勝”。如果 run A 的數(shù)字都比 run B 的數(shù)字小,那么 run A 的數(shù)字最后會待在原來的位置上。合并這兩個 run 需要做大量的工作,但并沒有產(chǎn)生任何結(jié)果。

排序的數(shù)據(jù)通常會有一些預(yù)先存在的內(nèi)部結(jié)構(gòu)。Timsort 假設(shè)如果 run A 的多個值小于 run B 的值,那么很可能 A 的值都小于 B 的值。

在示例中,run A 和 run B 必須嚴(yán)格遞增或遞減。

Timsort 將進(jìn)入奔馳(gallop)模式。Timsort 不檢查 A[0] 和 B[0] 之間的相互關(guān)系,而是進(jìn)行二分查找,以便找出 B[0] 在 A[0] 中的位置。這樣,Timsort 就可以將 A 的整個部分移動到合適的位置。然后,Timsort 在 B 中搜索 A[0] 的位置,再將 B 的整個部分移動到適當(dāng)?shù)奈恢谩?/p>

讓我們來看看它是如何運行的。Timsort 檢查 B[0](即 5),并使用二分查找找出它在 A 中的位置。

可以看到,B[0] 在 A 的尾部。然后,Timsort 檢查 A[0](即 1)在 B 中的位置??梢钥吹?#xff0c;數(shù)字 1 在 B 的開頭。我們現(xiàn)在知道 B 在 A 的尾部,A 在 B 的開頭。

事實證明,如果 B[0] 的位置非常接近 A 的開頭,那這么做就不值得,反之亦然。如果是這種情況,它就會快速退出奔馳模式。此外,Timsort 會把這個記下來,并通過增加連續(xù) A 或連續(xù) B 的數(shù)量來提高進(jìn)入奔馳模式的門檻。如果進(jìn)入奔馳模式是值得的,Timsort 會讓重新進(jìn)入奔馳模式變得容易些。

總的來說,Timsort 有兩個方面做得非常好:

對存在內(nèi)部結(jié)構(gòu)的數(shù)組排序有非常好的性能

能夠保持穩(wěn)定的排序

在以前,為了實現(xiàn)穩(wěn)定的排序,必須將列表中的項映射成整數(shù),并將其作為元組數(shù)組進(jìn)行排序。

代碼

如果你對代碼不感興趣,請?zhí)^這一部分。

Timsort 的原始源代碼:

https://github.com/python/cpython/blob/master/Objects/listobject.c 。

Python 已經(jīng)內(nèi)置了 Timsort 算法,要使用 Timsort,只需這樣寫:

或者:

如果你想掌握 Timsort 算法,我強(qiáng)烈建議你自己試著實現(xiàn)它!

https://skerritt.blog/timsort-the-fastest-sorting-algorithm-youve-never-heard-of/

點個在看少個 bug

總結(jié)

以上是生活随笔為你收集整理的java什么是稳定排序,这可能是你听说过最快的稳定排序算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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