Python 八大排序算法速度比較

這篇文章並非介紹排序算法原理的,純粹是想比較一下各類排序算法在真實場景下的運行速度。git

算法由 Python 實現,用到了一些語法糖,可能會和其餘語言有些區別,僅當參考就好。算法

測試的數據是自動生成的,以數組形式保存到文件中,保證數據源的一致性。shell

 

排序算法

 

直接插入排序

  • 時間複雜度:O(n²)
  • 空間複雜度:O(1)
  • 穩定性:穩定
def insert_sort(array):
    for i in range(len(array)):
        for j in range(i):
            if array[i] < array[j]:
                array.insert(j, array.pop(i))
                break
    return array

 

希爾排序

  • 時間複雜度:O(n)
  • 空間複雜度:O(n√n)
  • 穩定性:不穩定
def shell_sort(array):
    gap = len(array)
    while gap > 1:
        gap = gap // 2
        for i in range(gap, len(array)):
            for j in range(i % gap, i, gap):
                if array[i] < array[j]:
                    array[i], array[j] = array[j], array[i]
    return array

 

簡單選擇排序

  • 時間複雜度:O(n²)
  • 空間複雜度:O(1)
  • 穩定性:不穩定
def select_sort(array):
    for i in range(len(array)):
        x = i  # min index
        for j in range(i, len(array)):
            if array[j] < array[x]:
                x = j
        array[i], array[x] = array[x], array[i]
    return array

 

堆排序

  • 時間複雜度:O(nlog₂n)
  • 空間複雜度:O(1)
  • 穩定性:不穩定
def heap_sort(array):
    def heap_adjust(parent):
        child = 2 * parent + 1  # left child
        while child < len(heap):
            if child + 1 < len(heap):
                if heap[child + 1] > heap[child]:
                    child += 1  # right child
            if heap[parent] >= heap[child]:
                break
            heap[parent], heap[child] = \
                heap[child], heap[parent]
            parent, child = child, 2 * child + 1

    heap, array = array.copy(), []
    for i in range(len(heap) // 2, -1, -1):
        heap_adjust(i)
    while len(heap) != 0:
        heap[0], heap[-1] = heap[-1], heap[0]
        array.insert(0, heap.pop())
        heap_adjust(0)
    return array

 

冒泡排序

  • 時間複雜度:O(n²)
  • 空間複雜度:O(1)
  • 穩定性:穩定
def bubble_sort(array):
    for i in range(len(array)):
        for j in range(i, len(array)):
            if array[i] > array[j]:
                array[i], array[j] = array[j], array[i]
    return array

 

快速排序

  • 時間複雜度:O(nlog₂n)
  • 空間複雜度:O(nlog₂n)
  • 穩定性:不穩定
def quick_sort(array):
    def recursive(begin, end):
        if begin > end:
            return
        l, r = begin, end
        pivot = array[l]
        while l < r:
            while l < r and array[r] > pivot:
                r -= 1
            while l < r and array[l] <= pivot:
                l += 1
            array[l], array[r] = array[r], array[l]
        array[l], array[begin] = pivot, array[l]
        recursive(begin, l - 1)
        recursive(r + 1, end)

    recursive(0, len(array) - 1)
    return array

 

歸併排序

  • 時間複雜度:O(nlog₂n)
  • 空間複雜度:O(1)
  • 穩定性:穩定
def merge_sort(array):
    def merge_arr(arr_l, arr_r):
        array = []
        while len(arr_l) and len(arr_r):
            if arr_l[0] <= arr_r[0]:
                array.append(arr_l.pop(0))
            elif arr_l[0] > arr_r[0]:
                array.append(arr_r.pop(0))
        if len(arr_l) != 0:
            array += arr_l
        elif len(arr_r) != 0:
            array += arr_r
        return array

    def recursive(array):
        if len(array) == 1:
            return array
        mid = len(array) // 2
        arr_l = recursive(array[:mid])
        arr_r = recursive(array[mid:])
        return merge_arr(arr_l, arr_r)

    return recursive(array)

 

基數排序

  • 時間複雜度:O(d(r+n))
  • 空間複雜度:O(rd+n)
  • 穩定性:穩定
def radix_sort(array):
    bucket, digit = [[]], 0
    while len(bucket[0]) != len(array):
        bucket = [[], [], [], [], [], [], [], [], [], []]
        for i in range(len(array)):
            num = (array[i] // 10 ** digit) % 10
            bucket[num].append(array[i])
        array.clear()
        for i in range(len(bucket)):
            array += bucket[i]
        digit += 1
    return array

 

速度比較

from random import random
from json import dumps, loads


# 生成隨機數文件
def dump_random_array(file='numbers.json', size=10 ** 4):
    fo = open(file, 'w', 1024)
    numlst = list()
    for i in range(size):
        numlst.append(int(random() * 10 ** 10))
    fo.write(dumps(numlst))
    fo.close()


# 加載隨機數列表
def load_random_array(file='numbers.json'):
    fo = open(file, 'r', 1024)
    try:
        numlst = fo.read()
    finally:
        fo.close()
    return loads(numlst)
數據生成函數
from _datetime import datetime


# 顯示函數執行時間
def exectime(func):
    def inner(*args, **kwargs):
        begin = datetime.now()
        result = func(*args, **kwargs)
        end = datetime.now()
        inter = end - begin
        print('E-time:{0}.{1}'.format(
            inter.seconds,
            inter.microseconds
        ))
        return result

    return inner
顯示執行時間

若是數據量特別大,採用分治算法的快速排序和歸併排序,可能會出現遞歸層次超出限制的錯誤。json

解決辦法:導入 sys 模塊(import sys),設置最大遞歸次數(sys.setrecursionlimit(10 ** 8))。數組

@exectime
def bubble_sort(array):
    for i in range(len(array)):
        for j in range(i, len(array)):
            if array[i] > array[j]:
                array[i], array[j] = array[j], array[i]
    return array


array = load_random_array()
print(bubble_sort(array) == sorted(array))

↑ 示例:測試直接插入排序算法的運行時間,@exectime 爲執行時間裝飾器。app

算法執行時間

算法速度比較

相關文章
相關標籤/搜索