4000字總結迄今為止大多數排序的精華

2021-10-25 15:57:50 字數 3677 閱讀 8519

基於』比較交換『的排序規則

時間複雜度 o(n^2)

空間複雜度 o(1)

演算法穩定,排完序後相同關鍵字的相對順序沒有改變

基於』比較交換『的排序規則

每次找出還未排序的部分中的最大值放在末尾

詳情傳送門

時間複雜度 o(n^2)

空間複雜度 o(1)

演算法穩定,排完序後相同關鍵字的相對順序沒有改變

基於』比較交換『的排序規則

樹必須是完全二叉樹,可以用陣列來實現

演算法基於左右兩棵子樹都是堆,所以演算法應該是從最小子樹開始,最後乙個元素的一半即為該元素的父結點,也是最小子樹,且左右兩顆子樹皆為完整堆(只有乙個元素)

優勢:即使是最壞的情況下,時間複雜度仍為o(nlogn)

空間複雜度為o(1)

這裡說明一下空間複雜度為啥是o(1)

假設要求公升序

則可以構建乙個最大堆,出堆時的操作為返回根結點的值並將陣列的最後乙個元素移到根結點,此時根結點的左右子樹都為完整堆,故可以構成新的堆,再將元素個數-1。

關鍵來了,此時堆如果是陣列的話,那麼最後乙個空間儲存的就是這個陣列的最大值,且因為元素個數減掉了1,所以後面的迴圈不會改變這個數的位置,可以模擬下冒泡,都是從後面開始排。

這裡是不是有個疑惑:既然堆排在最壞情況下時間複雜度都是o(nlogn) 且空間複雜度為o(1),那麼為啥應用最廣泛的是快排而不是堆排?

快取利用率低

很簡單,堆排的時候,資料都是跳躍式的移動,而快排則是盡快的移動到最終的位置,然後做小範圍的跳動。所以快排更容易快取命中。

平均時間上快排還是要快一點

平均時間上,堆排序的時間常數比快排要大一些,因此通常會慢一些,但是堆排序最差時間也是o(nlogn)的,這點比快排好。

簡而言之就是選擇乙個基本元,然後將資料分為3部分

比基本元小的數 < 基本元 < 比基本元大的數

其中比較不固定的地方就是基本元的選取,目前應用最廣的有兩種方式,隨機數,中位數,考慮到隨機數的開銷,這裡還是推薦中位數

優點:平均時間最快,時間複雜度為o(nlogn),空間複雜度為o(1)

有個老哥寫的很好傳送門

快排的前身是歸併,而正是因為歸併存在不可忽視的缺點,才產生了快排。歸併的最大問題是需要額外的儲存空間,並且由於合併過程不確定,致使每個元素在序列中的最終位置上不可預知的。針對這一點,快速排序提出了新的思路:把更多的時間用在「分」上,而把較少的時間用在「治」上。從而解決了額外儲存空間的問題,並提公升了演算法效率。

快排之所以被稱為「快」排,是因為它在平均時間上說最快的,主要原因是硬體方面的,每趟快排需要指定乙個「支點」(也就是作為分界點的值),一趟中涉及的所有比較都是與這個「支點」來進行比較的,那麼我們可以把這個「支點」放在暫存器裡,如此這般,效率自然大大提高。除此之外,快排的高效率與分治思想也是分不開的。

這裡提一點,因為快排用到了遞迴,所以對於硬體方面存在入棧出棧開銷,在資料規模很小的情況下,速度可能還沒有冒泡快。

缺點:極端情況下時間複雜度會上公升為o(n^2)

快排的時間複雜度主要依賴主元的選取,如果主元每次剛好選在中間,那麼時間複雜度為nlogn,如果主元每次都選在了最大值或最小值的位置,那麼就是n方了。

時間複雜度o(nlogn)

空間複雜度o(取決於你需要多少個指標)

這裡必須得是真的二叉樹了,無法用陣列代替,所以有乙個天然的劣勢就是額外的資料開銷,至少包含乙個左子樹的指標和乙個右子樹的指標。

但是它的好處可太多了

首先它解決了陣列的插入困難,在陣列中每次要插入乙個數你得將這個數後面的資料依次向後面移乙個位置,然後再進行插入

其次它解決了鍊錶的查詢困難在鍊錶中如果要查詢乙個數得遍歷整個鍊錶而無法像陣列一樣下標查詢

最重要的是它提供了額外的資料,這一點是堆排無法提供的如果我們查詢到乙個數,我們同樣可以知道這個數的larger和smaller,且是最接近的那個,訪問也很簡單,分別為它的左子樹和右子樹的key。

說了這麼多但還是沒有說咋個排序,很簡單,用我們剛學樹的時候就知道的知識–中序遍歷,至於為什麼你試一下就知道來

很多人剛開始學歸併的時候會覺得歸併只能用陣列實現,其實並不是,鍊錶一樣可以

有一種方法叫快慢指標法傳送門

好處:歸併是典型的外排演算法(排序期間全部物件個數太多,不能同時存放在記憶體,必須根據排序過程的要求,不斷在內、外存之間移動的排序),有個老哥寫的不錯傳送門

應對於資料量非常大的資料,這些資料放在硬碟上,無法一次性的放到記憶體上。所以,我們通常對這些資料進行切分,然後將切分出來的小檔案讀進記憶體進行快排,最後得到的就是一堆排好序的小檔案,然後在從其中兩個檔案中乙個乙個讀資料進行歸併,邊讀邊存

缺點:需要額外的o(n)輔助空間,這點沒有快排好,但是快排無法處理這種大檔案問題

穩定性:穩定

目前以上的演算法,最快時間複雜度也是o(nlogn),有沒有一種更快的演算法

有,計數排序的時間複雜度為o(n+k)n為資料規模,k為資料範圍

需要提一下的是

對於』比較交換『類的演算法,它的好處就是幾乎不需要額外的空間,但同樣的時間複雜度被卡在了o(nlogn)

但是計數排序是基於』一眼掃過『整個陣列,記錄下每個數出現的次數,再進行排序的演算法

計數排序雖然快,但是缺點一大堆

1.需要提前知道資料規模和資料範圍

2.假如有兩個相同的數,你無法區別先後關係,因為陣列裡只會記錄這個數出現的次數不會記錄先後關係 ,需要需要記錄先後關係的話,歸併是個不錯的選擇

3.資料規模不能太大,記憶體無法一口氣存下這麼大規模的資料

4.不適用於帶有負數的排序,需要額外的邏輯開銷,得不償失

在計數排序基礎上建立的排序,時間複雜度仍然是線性

思想就是按位排序,先排最低位,最後排最高位傳送門

缺點:1.還是沒有解決存在負數的問題

其餘問題都得到了解決是計數排序的優化版本

目前最優的增量序列可以使時間複雜度降為o(n^4/3)

具體實現直接去看mooc的浙大資料結構就好

缺點:如果增量序列選擇不好,時間複雜度甚至比插入排序還慢,如

在以下的陣列中,前面在1間隔之前,沒有做任何交換

在8間隔中下標為0,8的值為1,5為有序的,沒有進行交換

下標為1,9的值為9,13為有序,也沒有進行交換

同理在1間隔之前陣列還是原來的陣列,這時進行排序其實就是插入排序

我迄今為止寫的最長的SQL

今天看我14年實習的時候,當時我的導師在部落格中寫到了一段差不多50多行的sql,說是他寫的最長的sql,想想工作的這一年,其實我也寫了不少sql,因為自身是做資料開發方面的工作,寫sql是免不了的,哈哈 今天剛好是五一假後上班的第一天,也不想幹什麼事,就寫寫部落格吧,好久沒有記錄啦。好,言歸正傳,...

這可能是迄今為止對大前端最好的解釋

前端技術領域發展至今,已經不僅僅是 pc 端瀏覽器網頁的開發這麼簡單了。現在很流行乙個詞來形成前端技術領域,叫做大前端。但是,至少到目前為止我個人還沒有看到乙個對大前端的解釋非常不錯的。不過,接下來的內容我個人覺得是目前我看到對大前端的解釋是最好的了。向服務端進發 眾所周知,乙個完整的 web 應用...

迄今為止最通俗易懂的MVP架構講解

從mvc到mvp再到mvvp,相信大家就已經聽說過這些架構了。但你真正應用到哪個階段了呢?是不是還苦於網上對mvp晦澀的講解?今天,coder哥就用最通俗易懂的方式告訴你,mvp怎麼用!先上一張mvp結構圖。接下來就一步步教你用 1 首先把結構包分好,方便理清思路 2 定義model層的介面imod...