三種常用高級排序-堆排序,歸併排序,快速排序

常用的高級排序代碼整理

堆排序

基本思路

a.將無需序列構建成一個堆,根據升序降序需求選擇大頂堆或小頂堆;
b.將堆頂元素與末尾元素交換,將最大元素"沉"到數組末端;
c.重新調整結構,使其滿足堆定義,然後繼續交換堆頂元素與當前末尾元素,反覆執行調整+交換步驟,直到整個序列有序。

時間複雜度 空間複雜度 穩定性
最好 平均 最壞
O(nlogn) O(nlogn) O(nlogn) o(1) 不穩定
def sift(li,low,high):
    '''
    調整結構
    li:列表
    low:根節點
    high:子節點
    '''
    i = low # i最開始指向根節點
    j = 2 * i + 1 # j開始是左孩子節點
    tmp = li[i]
    while j <= high: #j超過最後一個節點,只要j位置有數就執行
        if j + 1 <= high and li[j+1] > li[j]: #如果右子節點大於左子節點,且右子節點存在
            j = j + 1   #j指向較大的節點(右子節點)
        if li[j] > tmp:
            li[i] = li[j]     #往下看一層,看子節點是否滿足堆的條件
            i = j 
            j = i * 2 + 1
        else:       # tmp更大,則將tmp放在當前i的位置
            li[i] = tmp
            break
    else:
        li[i] = tmp # 把tmp放在最後
        
def heap_sort(li):
    n=len(li)
    for i in range((n-2)//2,-1,-1): #i表示建立堆的時候調整部分的根的下標
        sift(li,i,n-1)       #始終使用最後一個元素作爲high,不會影響判斷
    for i in range(n-1,-1,-1):  #i指向當前堆的最後一個位置
        li[0],li[i] = li[i],li[0]     # 堆首和堆尾交換位置,將最大的放到堆尾
        sift(li,0,i-1)      #i-1是新的high

python內部堆排序函數

import heapq
import random
li = list(rangen(100)
heapq.heapify(li)   #建立堆
heapq.heappop(li)   #彈出最小的值            

使用場景:

  • 熱搜榜的取前幾名

自己實現topk問題

基本思路

將前k個數建堆,從k+1個數開始遍歷替換堆中的根節點並且調整堆,最後堆中留下來的元素就是最大或者最小且有序的

def sift(li,low,high):
    '''
    li:列表
    low:根節點
    high:子節點
    '''
    i = low # i最開始指向根節點
    j = 2 * i + 1 # j開始是左孩子節點
    tmp = li[i]
    while j <= high: #j超過最後一個節點,只要j位置有數就執行
        if j + 1 <= high and li[j+1] < li[j]: #如果右子節點大於左子節點,且右子節點存在
            j = j + 1   #j指向較大的節點(右子節點)
        if li[j] < tmp:
            li[i] = li[j]     #往下看一層,看子節點是否滿足堆的條件
            i = j 
            j = i * 2 + 1
        else:       # tmp更大,則將tmp放在當前i的位置
            li[i] = tmp
            break
    else:
        li[i] = tmp # 把tmp放在最後

        
        
def topk(li,k):
    heap = li[0:k]
    for i in range((k-2)//2,-1,-1):
        sift(heap,i,k-1)    
    #建堆
    for i in range(k,len(li)-1):
        if li[i] > heap[0]:
            heap[0] = li[i]
            sift(heap,0,k-1)
    # 遍歷尋找topk
    for i in range(k-1,-1,-1):
        heap[0],heap[i] = heap[i],heap[0]
        sift(heap,0,i-1)
    #出數
    return heap

歸併排序

基本思路

歸併的基本思路在於先分解再合併,將數組分解爲左右兩個有序數組,然後將有序數組合併到一個數組中

時間複雜度 空間複雜度 穩定性
最好 平均 最壞
O(nlogn) O(nlogn) O(nlogn) o(n) 穩定

在這裏插入圖片描述

def merge(li,low,mid,high):
    '''
    合併左右兩個有序數組
    '''
    i = low
    j = mid + 1
    ltmp = []
    while i <= mid and j<=high:   # 從兩個數組的第一個元素開始,只要左右兩邊都有數
        if li[i] < li[j]:
            ltmp.append(li[i])
            i += 1
        else:
            ltmp.append(li[j])
            j +=1                   # 哪個元素小將其放入新數組的第一個
    while i<= mid:                  # 如果其中一邊的數組都已經遍歷完,則將另一邊的順序存入新數組中
        ltmp.append(li[i])
        i += 1
    while j<= high:
        ltmp.append(li[j])
        j += 1
    li[low:high+1] = ltmp           #將排好的新數組寫回到原數組

    
def merge_sort(li,low,high):
    if low < high:                  #如果數組中的元素大於1則遞歸
        mid = (high + low) // 2
        merge_sort(li,low,mid)
        merge_sort(li,mid+1,high)
        merge(li,low,mid,high)

快速排序

基本思路

在數組中選中一個元素,將素組中所有小於該元素的元素放入左邊,將大於該元素的元素放入右邊,將該元素放於交界處,在將左右兩邊的數組分別按照上述邏輯接着整理,直到最小單元。

時間複雜度 空間複雜度 穩定性
最好 平均 最壞
O(n^2) O(nlogn) O(nlogn) 平均O(logn)最壞o(n) 不穩定
# 這種實現方法不需要開闢新的數組儲存空間
def quick(li,left,right):
    '''
    將數組在區間內按照左中右排列
    '''
    i = left
    j = right
    base = li[i]
    while i < j:                           # 區間中還有元素
        while i<j and li[j] <= base:       # 將小於base的放在左邊base的空位
            j=j-1
        li[i] =li[j]
        while i<j and li[i] >= base:       #將大於base的放在右邊之前空出來的空位
            i = i + 1
        li[j] = li[i]
    li[i] = base                           #最後i=j的時候,將base放入
    return i                               # 返回中間值(base的索引)

def quick_sort(li,left,right):
    if left < right:
        mid = quick(li,left,right)
        quick_sort(li,left,mid - 1)
        quick_sort(li,mid + 1,right)

另一種快排

#這種需要佔用其他的數組儲存空間
def quick_sort2(li):
    if len(li)<2:
        return li
    else:
        base = li[0]
        lli = [i for i in li[1:] if i <=base]
        rli = [i for i in li[1:] if i >base]
        return quick_sort2(lli)+[base]+quick_sort2(rli)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章