十大排序算法(python實現(xiàn))【未完待續(xù)】

一蜡塌、排序算法分類

十大排序算法可以分為兩大類:
非線性時間排序:通過比較元素來決定元素間的相對次序,其時間復雜度不能突破O(nlogn)
線性時間排序:不通過比較元素來決定元素間的相對次序棋凳,可以突破比較排序時間下界弧关,以線性時間運行

其中:穩(wěn)定是指如果a原本在b前面两蟀,而a=b,排序之后a仍然在b的前面履澳,不穩(wěn)定是a可能會出現(xiàn)在b的后面。

二怀跛、非線性時間排序算法

1. 冒泡排序(Bubble Sort)

· 遍歷一遍距贷,比較相鄰元素大小,若元素順序錯誤則交換位置吻谋,一遍結(jié)束后忠蝗,一個元素的位置排好;
· 重復遍歷列表中未排序元素漓拾,直至完成列表排序阁最;(如果在一次遍歷中戒祠,沒有發(fā)生元素交換行為,則說明列表所有元素順序正確速种,排序完成)

每輪只對相鄰兩個數(shù)比較與交換姜盈,每輪會將一個最值交換到數(shù)據(jù)列首或尾,像冒泡一樣哟旗,n個數(shù)據(jù)會操作n-1輪贩据。時間復雜度O(n^2),額外空間開銷在交換數(shù)據(jù)時那一個過渡空間闸餐,空間復雜度O(1)饱亮。
代碼實現(xiàn):

def bubble_sort(arr):
        def swap(i, j):
            arr[i], arr[j] = arr[j], arr[i]
        
        n = len(arr)
        swapped = True    

        x = -1

        while swapped:
            swapped = False
            x = x + 1
            for i in range(1, n - x):
                if arr[i-1] > arr[i]:
                    swap(i-1, i)
                    swapped = True
                    
        return arr

2. 簡單選擇排序(Select Sort)

· 將輸入列表/數(shù)組分為兩部分:已經(jīng)排序的子列表和剩余要排序的子列表;
· 在未排序的子列表中找到最小的元素舍沙,并將其按順序放置在排序的子列表中近上,重復此過程,直至列表完全排序拂铡;

n個數(shù)操作n-1輪壹无,每輪選一個最值,時間復雜度O(n^2)感帅,額外空間開銷在交換數(shù)據(jù)時那一個過渡空間斗锭,空間復雜度O(1)。
代碼實現(xiàn):

def select_sort(arr):
        for i in range(len(arr)):
            minvalue_idx = i
            for j in range(i, len(arr)):
                if arr[j] < arr[minvalue_idx]:
                    minvalue_idx = j
            arr[i], arr[minvalue_idx] = arr[minvalue_idx], arr[i]
        return arr

3. 快速排序(Quick Sort)

· 從數(shù)組中挑出一個元素失球,稱為“基準”(pivot);
· 分區(qū):將所有比基準值小的元素擺放在基準值前岖是,比基準值大的元素擺在基準后值,基準值位于數(shù)列的中間位置实苞;
· 遞歸地把小于基準值的子數(shù)列和大于基準值的子數(shù)列排序普碎;

遞歸到最底部的判斷條件是數(shù)列的大小是0或者1想鹰,此時該數(shù)列顯然已經(jīng)有序窖剑。
選取基準值數(shù)種具體方法煤惩,其選取方法對排序的時間性能有關。常見會選取數(shù)組第一個數(shù)作為基準猾浦。

1)設置兩個變量i陆错、j,排序開始的時候:i=0, j=N-1金赦;
2)以第一個數(shù)組元素作為基準危号,賦值給pivot,即key=A[0]素邪;
3)從j開始向前搜索外莲,即由后向前搜索(j--),找到第一個小于pivot的A[j],將A[j]和A[i]互換偷线;
4)從i開始向后搜索磨确,即由前向后搜索(i++),找到第一個大于pivot的A[i]声邦,將A[i]和A[j]互換乏奥;
5)重復3、4步亥曹,直到i=j;(3,4步中邓了,沒找到符合條件的值,即3中的A[j]不小于pivot媳瞪,4中的A[i]不大于pivot時骗炉,改變i, j的值,j = j-1蛇受,i = i+1)

快排是原地排序句葵,不需要輔助數(shù)組,但是遞歸調(diào)用需要輔助棧兢仰≌д桑快速排序最好的情況下是每次都正好將數(shù)組對半分,這樣遞歸調(diào)用次數(shù)才是最少的把将,這種情況下比較次數(shù)為 Cn=2Cn/2+n轻专,復雜度為 O(nlogn)。最壞的情況下察蹲,第一次從最小的元素切分铭若,第二次從第二小的元素切分,如此這般递览。因此最壞的情況下需要比較n^2/2,為了防止數(shù)組從最開始就是有序的瞳腌,在進行快排時需要隨機打亂數(shù)組绞铃。

時間復雜度:快排涉及到遞歸調(diào)用,因此其時間復雜度與遞歸算法的復雜度相關嫂侍,T[n] = aT[n/b] + f(n) 儿捧。
最優(yōu)快排:每一次取到的元素都剛好平分整個數(shù)組,T[n] = 2T[n/2] + f(n)挑宠, T[n/2]為平分后的子數(shù)組的時間復雜度菲盾,f[n] 為平分這個數(shù)組時所花的時間。遞歸推算下來時間復雜度O( nlogn )各淀。最差的情況就是每次取到的元素是數(shù)組中最大/或者最小的懒鉴,此時時間復雜度O(n^2)。平均時間復雜度O(nlogn)。
空間復雜度:就地快速排序使用的空間O(1)临谱,是常數(shù)級璃俗,而真正消耗空間的就是遞歸調(diào)用,因為每次遞歸就要保持一些數(shù)據(jù)悉默。額外空間開銷出在暫存基準值,最優(yōu)情況下空間復雜度為O(logn)城豁,每次都平分數(shù)組,最差情況下空間復雜度為O(n)抄课,每次取到的元素是最值唱星。
代碼實現(xiàn):

def partition(arr, low, high):
        pivot = arr[low]
        while low < high:
            while low < high and arr[high] >= pivot:
                high = high -1
                
            arr[low] = arr[high]
            
            while low < high and arr[low] <= pivot:
                low = low + 1
                
            arr[high] = arr[low]
        
        arr[low] = pivot
        return low
                   
    def QucikSort(arr, low, high):
        if low >= high:
            return
        pivot_idx = partition(arr, low, high)
        QucikSort(arr, low, pivot_idx-1)
        QucikSort(arr, pivot_idx+1, high)
        return arr

4. 簡單插入排序(Insert Sort)

· 從第一個元素開始,該元素可被認為已經(jīng)被排序跟磨;
· 取出下一個元素间聊,在已經(jīng)排序的元素列表中從后向前掃描;
· 如果該已排序元素大于新元素吱晒,將新元素向前移動至下一位置甸饱;
· 重復上一步驟,直到找到已排序的元素小于或等于新元素的位置仑濒;
· 將新元素插入到該位置后叹话;

簡單插入排序需要操作n-1輪,每輪將一個未排序元素插入排好序列墩瞳,開始時默認第一個元素有序驼壶,將剩余n-1個數(shù)逐個插入。插入操作具體包括:比較確定插入位置喉酌,數(shù)據(jù)移位騰出合適空位热凹。
每輪操作O(n)次,共O(n)輪泪电,時間復雜度O(n^2)般妙;
額外空間開銷是數(shù)據(jù)移位時產(chǎn)生的一個過渡空間,空間復雜度為O(1)相速。

def InsertSort(arr):
    n = len(arr)
    if n<=1: return arr
    for i in range(1,n):
        j = i
        target = arr[i]
        while j>0 and target<arr[j-1]:
            arr[j]=arr[j-1]
            j=j-1
        arr[j] = target
    return arr

5. 堆排序(Heap Sort)

堆排序是利用堆這種數(shù)據(jù)結(jié)構而設計的一種排序算法碟渺,堆排序是一種選擇排序。堆是具有以下性質(zhì)的完全二叉樹:每個結(jié)點的值都大于或等于其左右孩子結(jié)點的值突诬,稱為大頂堆苫拍;每個結(jié)點的值都小于或等于其左右孩子結(jié)點的值,稱為小頂堆旺隙。


對堆中的結(jié)點按層進行編號绒极,將這種邏輯結(jié)構映射到數(shù)組中如下:

該數(shù)組從邏輯上講就是一個堆結(jié)構,用公式來描述堆的定義就是:
大頂堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
小頂堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

堆排序的基本思想:將待排序序列構造成一個大頂堆蔬捷,此時垄提,整個序列的最大值就是堆頂?shù)母?jié)點。將其與末尾元素進行交換,此時末尾就為最大值塔淤。然后將剩余n-1個元素重新構造成一個堆摘昌,這樣就會得到n個元素的次小值。如此反復執(zhí)行高蜂,便能得到一個有序序列聪黎。
步驟一、構造初始堆:將給定無序序列構造成一個大頂堆(一般升序采用大頂堆备恤,降序采用小頂堆)

  1. 假設給定無序序列結(jié)構如下:
  1. 此時從最后一個非葉子結(jié)點開始(葉結(jié)點自然不用調(diào)整稿饰,第一個非葉子節(jié)點len(arr)/2-1 = 5/2-1=1,也就是下面的6結(jié)點)露泊,從左至右喉镰,從下至上進行調(diào)整。
  1. 找到第二個非葉子節(jié)點4惭笑,其中4,9,8中9最大侣姆,4和9交換。

此時沉噩,交換導致了子根4,5,6結(jié)構混亂捺宗,繼續(xù)調(diào)整,4,5,6中6最大川蒙,4和6交換位置蚜厉,將無序序列構造成了一個大頂堆。

步驟二畜眨、將堆頂元素與末尾元素進行交換昼牛,使末尾元素最大,然后繼續(xù)調(diào)整堆康聂,再將堆頂元素與末尾元素交換贰健,得到第二大元素,如此反復進行交換恬汁、重建伶椿、交換,直到整個序列有序蕊连。

  1. 將堆頂元素9與末尾元素4進行交換
  1. 重新調(diào)整結(jié)構,使其繼續(xù)滿足堆定義
  1. 再將堆頂元素8與末尾元素5進行交換游昼,得到第二大元素8

后續(xù)過程甘苍,繼續(xù)進行調(diào)整、交換烘豌,如此反復進行载庭,最終使得整個序列有序。

總結(jié):
· 將無序序列構建成一個堆,根據(jù)升序囚聚、降序需求選擇大頂堆或小頂堆靖榕;
· 將堆頂元素與末尾元素交換,將最大元素“沉”到數(shù)組末端顽铸;
· 重新調(diào)整結(jié)構茁计,使其滿足堆定義,然后繼續(xù)交換堆頂元素與當前末尾元素谓松,反復執(zhí)行調(diào)整+交換步驟星压,直到整個序列有序;

def heapify(arr, n, i):
    largest = i
    l = 2 * i + 1
    r = 2 * i +2
            
    if l < n and arr[i] < arr[l]:
        largest = l
            
    if r < n and arr[largest] < arr[r]:
        largest = r
            
    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i] #exchange
                
        heapify(arr, n, largest)
        
def heapSort(arr):
    n = len(arr)
    
    # Build a maxheap
    for i in range(n, -1, -1):
        heapify(arr, n, i)
            
    # exchange the max to the end
    for i in range(n-1, 0, -1):
        arr[i], arr[0] = arr[0], arr[i]
        heapify(arr, i, 0)

6. 希爾排序(Shell Sort)

7. 歸并排序(Merge Sort)

歸并排序是建立在歸并操作上的一種有效的排序方法鬼譬,該算法是分治法(Divide and Conquer)的一個非常典型的應用娜膘。先使每個子序列有序,再將兩個有序子序列合并成一個有序序列稱為2-路歸并优质。

· 把長度為n的輸入序列分成為兩個長度為n/2的子序列竣贪;
· 對這兩個子序列分別采用歸并排序;
· 將兩個排好序的子序列合并成一個最終的排序序列巩螃;

歸并排序包括了Sort和Merge兩部分演怎。當有n個待排序元素時,需要進行l(wèi)ogn輪歸并排序牺六,每一輪歸并颤枪,其比較元素不超過n個,因此歸并排序時間復雜度為nlogn淑际;而在排序時需記錄的中間元素個數(shù)與待排序元素個數(shù)相等畏纲,因此空間復雜度為O(n)。

def merge_sort(arr, low, high):
    if low >= high: return
    mid = (low + high) // 2
    merge_sort(arr, low, mid)
    merge_sort(arr, mid+1, high)
    merge(arr, low, mid, high)
        
def merge(arr, low, mid, high):
    container = []
    i, j = low, mid + 1
    while i<=mid and j<=high:
        if arr[i] <= arr[j]:
            container.append(arr[i])
            i = i + 1
        else:
            container.append(arr[j])
            j = j + 1
        if i<=mid:
            container.extend(arr[i:mid+1])
        elif j<=high:
            container.extend(arr[j:high+1])
    arr[low:high+1] = container

三春缕、線性時間排序算法

1. 計數(shù)排序(Counting Sort)

2. 桶排序(Bucket Sort)

3. 基數(shù)排序(Radix Sort)

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末盗胀,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子锄贼,更是在濱河造成了極大的恐慌票灰,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宅荤,死亡現(xiàn)場離奇詭異屑迂,居然都是意外死亡,警方通過查閱死者的電腦和手機冯键,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門惹盼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人惫确,你說我怎么就攤上這事手报◎遣眨” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵掩蛤,是天一觀的道長枉昏。 經(jīng)常有香客問我,道長揍鸟,這世上最難降的妖魔是什么兄裂? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮蜈亩,結(jié)果婚禮上懦窘,老公的妹妹穿的比我還像新娘。我一直安慰自己稚配,他們只是感情好畅涂,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著道川,像睡著了一般午衰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上冒萄,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天臊岸,我揣著相機與錄音,去河邊找鬼尊流。 笑死帅戒,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的崖技。 我是一名探鬼主播逻住,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼迎献!你這毒婦竟也來了瞎访?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤吁恍,失蹤者是張志新(化名)和其女友劉穎扒秸,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體冀瓦,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡伴奥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了翼闽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拾徙。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖肄程,靈堂內(nèi)的尸體忽然破棺而出锣吼,到底是詐尸還是另有隱情,我是刑警寧澤蓝厌,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布玄叠,位于F島的核電站,受9級特大地震影響拓提,放射性物質(zhì)發(fā)生泄漏读恃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一代态、第九天 我趴在偏房一處隱蔽的房頂上張望寺惫。 院中可真熱鬧,春花似錦蹦疑、人聲如沸西雀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽艇肴。三九已至,卻和暖如春叁温,著一層夾襖步出監(jiān)牢的瞬間再悼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工膝但, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留冲九,地道東北人。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓跟束,卻偏偏與公主長得像莺奸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子泳炉,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355