從零開始學演算法:3.排序演算法
作者: tiankonguse | 更新日期:
演算法還是需要重新拾起來,這裡以排序演算法作為嘗試吧。
一、背景
大家好,我是tiankonguse。
由於某些原因,經常有人想要學習演算法,但是自己之前又沒有相關經驗,不知道從何做起。 我思考了許久,計劃寫一個系列來分享如何入門學習演算法。
上半年的時候就分享了《 認識演算法 》和《 瞭解套路長啥樣 》,本想接下來按專題進行分享,思考良久卻發現對於演算法,寫文章不太好講清楚,當面講或者視訊講效果才是最佳的。
另外大部分演算法感覺太簡單,廣度與深度都不好把握,於是自己內心比較矛盾,糾結了一段時間這個事情就給耽擱了。
現在又到了開學季,演算法還是需要重新拾起來,這裡以排序演算法作為嘗試吧。
二、基本知識
排序,顧名思義,就是把一串資料按照特定的排序方式進行排列的一種演算法。
排序演算法的輸出必須滿足兩個原則:輸出序列有序、輸出序列是輸入序列的一種排列組合。
一般情況下,排序演算法是通用的,不管什麼資料,按照這個演算法都可以得到預期結果。
所以我們往往使用整數序列作為例子來分析排序演算法是如何執行的,排序後的結果是整數滿足遞增。
下面我們就分別來看看常見的排序演算法吧。
三、氣泡排序
氣泡排序是一種最容易理解的排序演算法。
這個演算法的基本思想如下:
1.比較相鄰元素,如果第一個比第二個大,就交換他們。
2.對每一個相鄰的元素做同樣的操作,從第一個到最後一個。做完之後最後一個就是最大值。 3.針對所有元素重複以上步驟,除了最後一個。
4.持續步驟1~3,每次都會少一個數字,直到剩餘一個數字為止。
如上圖,外層迴圈每執行一次, [0, i] 之間通過若干次交換,i 位置變成了最大值。
如果你看其他人的氣泡排序,可能會發現 i 是從小到大迴圈的,其實會發現從大到小會更清晰。
複雜度:由於有兩層迴圈,只不過每次比上次少迴圈1 次, 不過複雜度還是 O(n^2)。
四、選擇排序
選擇排序和氣泡排序想法很像,都是迴圈序列,使得當前的序列的最大值處於一端。
先看氣泡排序,依次比較的時候,如果不滿足增序,會修改中間狀態的值。
而選擇排序則是每次挑出最大值的位置,然後只交換一次。
具體思想如下:
1.遍歷序列,選出當前序列的最大值,和最後一個交換。 2.不包含最後一個數字的序列重複步驟1。
3.每次數字少一個,直到數字剩一個為止。
複雜度:這個和冒泡演算法的複雜度一樣,也是O(n^2)。
五、插入排序
插入排序和冒泡也很類似,只不過冒泡每次都是在亂序序列內遍歷,而插入排序則是在已排序的序列上掃描。
具體思想如下:
1.取第一個元素,認為已經排序。
2.取下個元素,在已經排序的序列中從後向前掃描。
3.如果該元素大於新元素,將該元素移到下一位。
4.重複步驟3,直到找到已排序的元素小於或等於新元素。
5.將新元素插入到該元素位置後面。
6.重複步驟2~5。
複雜度:依舊是O(n^2)。
六、歸併排序
歸併排序是分治法的一個經典應用。
基本思想是: 1.將序列平均分為兩個子序列。
2.分別遞迴呼叫這個排序演算法,使得子序列有序。 3.合併兩個有序的子序列。
這裡複雜度涉及到遞迴計算,公式是 f(n) = 2 * f(n/2) + n,一般使用遞迴樹來計算。
對於f(n)的複雜度,有合併的O(n)和兩個子陣列 f(n/2) 得到。
而每個f(n/2) 也都是有合併的O(n/2) 和兩個子子陣列 f(n/2) 得到。 全部展開後如下圖,總複雜度就是各個節點的合併複雜度之和,恰好每層的和是 O(n),共有 log(n) 層,所以總複雜度是 O(n log(n))。
七、快速排序
歸併排序是先將序列從中間分兩部分分別遞迴排序,然後再合併在一起。
而快速排序是另一種遞迴排序,我們來看看。
基本思想:
1.從序列中隨機跳一個數字。 2.重新排列序列,將序列按照挑的數字分兩部分,前一部分小於這個數字,後一部分大於等於這個數字。 3.步驟2得到的兩個子序列分別按照步驟一和步驟二遞迴執行,直到數字為一個。
快排和歸併排序類似,都是分而治之,所以複雜度都是O(n log(n)),不過對於快排,在極端情況會導致複雜度是O(n^2)。
八、堆排序
堆是一種很有用的樹形資料結構,
以最大堆為例,堆的父節點必須大於兩個子節點,遞迴推理,我們可以得出堆的頂點就是最大值。 由於堆是標準的樹,所以對節點的操作複雜度最壞情況是O(log(n)),我們依次從頂點取出最大值即可得到一個有序的序列,最終複雜度是O(n log(n))。
而構造堆也是一個一個節點插入的,所以構造堆的複雜度也是O(n log(n))。
排序的具體思想如下: 1.依次構建最大堆。
2.將堆頂元素與堆的最後一個元素交換,堆的大小減一、維護堆滿足堆的特性。 3.重複步驟二,直到堆只剩一個元素。
九、其他排序
排序的方法很多,如計數排序、桶排序、基數排序、希爾排序。
另外排序還涉及到時間複雜度、空間複雜度、是否是穩定排序等,這裡就不介紹了。
接下來我想想該分享啥演算法,太基礎了會感覺太簡單,太難了文字又不好講,確實很糾結。
本文首發於公眾號:天空的程式碼世界,微信號:tiankonguse-code。
推薦閱讀:
今天長按識別上面的二維碼,在公眾號中回覆“ ACM模板 ”,你將免費獲得我大學耗時四年整理的《ACM演算法模板》。
回覆“ 演算法的世界 ”,或點選 閱讀原文 加入“tiankonguse的朋友們”,已有三百多個小夥伴加入。