詳解排序算法(Python實現)

sorting-algorithms-python

Python的內置排序算法

與許多其他高級編程語言一樣,Python語言提供了使用sorted()函數對數據進行開箱即用的功能。示例:

>>> li = [9, 5, 3, 6, 7]
>>> sorted(li)
[3, 5, 6, 7, 9]

冒泡排序

冒泡排序是最直接的排序算法之一。它的名稱來自算法的工作方式:每經過一次便利,列表中最大的元素就會“冒泡”至正確位置。

冒泡排序包括:遍歷一個列表,一次比較元素,以及交換不規則的相鄰項。

Python實現冒泡排序

def bublle_sort(array):
	n = len(array)
	
	for i in range(n):
		# 創建一個標誌位
		already_sorted = True
	
		for j in range(n - i - 1):
			if array[j] > array[j+1]:
				array[j], array[j+1] = array[j+1], array[j]
				already_sorted = False
		if already_sorted:
            break
     return array

時間複雜度:O(n2n^2).

插入排序

像冒泡排序一樣,插入排序算法也易於實現和理解。但是與冒泡排序不同,它通過將每個項目與列表的其餘部分進行比較並將其插入正確的位置,來一次構建一個排序的列表元素。此“插入”過程爲算法命名。

解釋插入排序的一個很好的類比是您對一副紙牌進行排序的方式。想象一下,您手裏拿着一組卡片,並且想要按順序排列它們。首先,將一張卡片與其餘卡片進行逐步比較,直到找到正確的位置爲止。屆時,您需要將卡插入正確的位置,然後重新開始製作新卡,重複進行直到您手上的所有卡都被排序爲止。

Python實現插入排序

def insertion_sort(array):
	for i in range(1, len(array)):
		key_item = array[i]
		j = i - 1
		
		while j >= 0 and array[j] > key_item:
			array[j + 1] = array[j]
			j -= 1
		
		array[j + 1] = key_item
	
	return arry

時間複雜度:O(n2n^2).

歸併排序

歸併排序是一種非常有效的排序算法。它基於分治法,這是一種用於解決複雜問題的強大算法技術。

爲了正確理解分而治之,您應該首先了解遞歸的概念。遞歸涉及將問題分解爲較小的子問題,直到它們足夠小以至於無法解決。在編程中,遞歸通常由調用自身的函數表示。

分而治之算法通常遵循相同的結構:

  1. 原始輸入分爲幾個部分,每個部分代表一個子問題,該子問題與原始輸入相似,但更爲簡單。
  2. 每個子問題都遞歸解決。
  3. 所有子問題的解決方案都組合成一個整體解決方案。

在歸併排序的情況下,分而治之的方法將輸入值的集合劃分爲兩個大小相等的部分,對每個一半進行遞歸排序,最後將這兩個排序的部分合併爲一個排序列表。

Python實現歸併

def merge(left, right):
	if len(left) == 0:
		return right
	
	if len(right) == 0:
		return left
	
	result = []
	index_left = index_right = 0
	
	while len(result) < len(left) + len(right):
		if left[index_left] <= right[index_right]:
			result.append(left[index_left])
			index_right += 1
		else:
			result.append(right[index_right])
			index_left += 1
		
		 if index_right == len(right):
            result += left[index_left:]
            break

        if index_left == len(left):
            result += right[index_right:]
            break

    return result

def merge_sort(array):
    if len(array) < 2:
        return array

    midpoint = len(array) // 2
    
    return merge(
        left=merge_sort(array[:midpoint]),
        right=merge_sort(array[midpoint:]))

時間複雜度: O(nlognn logn)

快速排序

就像合併排序一樣,快速排序算法採用分而治之的原理將輸入數組分爲兩個列表,第一個包含小項目,第二個包含大項目。然後,該算法將對兩個列表進行遞歸排序,直到對結果列表進行完全排序爲止。

劃分輸入列表稱爲對列表進行分區。Quicksort首先選擇一個樞軸元素,然後將列表圍繞該樞軸進行分區,將每個較小的元素放入一個低數組,將每個較大的元素放入一個高數組。

將每個元素從低位列表放置到數據透視表的左側,將每個元素從高位列表放置在數據透視表的右側,將其精確定位在最終排序列表中需要的位置。這意味着函數現在可以遞歸地將相同的過程遞歸地從低到高,直到對整個列表進行排序。

Python實現快速排序

rom random import randint

def quicksort(array):
    # If the input array contains fewer than two elements,
    # then return it as the result of the function
    if len(array) < 2:
        return array

    low, same, high = [], [], []

    # Select your `pivot` element randomly
    pivot = array[randint(0, len(array) - 1)]

    for item in array:
        # Elements that are smaller than the `pivot` go to
        # the `low` list. Elements that are larger than
        # `pivot` go to the `high` list. Elements that are
        # equal to `pivot` go to the `same` list.
        if item < pivot:
            low.append(item)
        elif item == pivot:
            same.append(item)
        elif item > pivot:
            high.append(item)

    # The final result combines the sorted `low` list
    # with the `same` list and the sorted `high` list
    return quicksort(low) + same + quicksort(high)

時間複雜度: O(nlognn logn)

Timsort algorithm

Timsort算法被認爲是一種混合排序算法,因爲它採用了插入排序和合並排序的兩全其美組合。Timsort與Python社區近在咫尺,因爲它是由Tim Peters在2002年創建的,被用作Python語言的標準排序算法。

Timsort的主要特徵是它利用了大多數現實數據集中存在的已排序元素。這些稱爲自然運行。然後,該算法會遍歷列表,將元素收集到運行中,然後將它們合併到一個排序的列表中。

Python 實現Timsort

在本部分中,您將創建一個準系統的Python實現,該實現說明Timsort算法的所有部分。如果您有興趣,也可以查看Timsort的原始C實現

def insertion_sort(array, left=0, right=None):
    if right is None:
        right = len(array) - 1

    # Loop from the element indicated by
    # `left` until the element indicated by `right`
    for i in range(left + 1, right + 1):
        # This is the element we want to position in its
        # correct place
        key_item = array[i]

        # Initialize the variable that will be used to
        # find the correct position of the element referenced
        # by `key_item`
        j = i - 1

        # Run through the list of items (the left
        # portion of the array) and find the correct position
        # of the element referenced by `key_item`. Do this only
        # if the `key_item` is smaller than its adjacent values.
        while j >= left and array[j] > key_item:
            # Shift the value one position to the left
            # and reposition `j` to point to the next element
            # (from right to left)
            array[j + 1] = array[j]
            j -= 1

        # When you finish shifting the elements, position
        # the `key_item` in its correct location
        array[j + 1] = key_item

    return array

此修改後的實現添加了左右兩個參數,這些參數指示應對數組的哪一部分進行排序。這使Timsort算法可以對數組的一部分進行排序。修改功能而不是創建新功能意味着可以將其同時用於插入排序和Timsort。

def timsort(array):
    min_run = 32
    n = len(array)

    # Start by slicing and sorting small portions of the
    # input array. The size of these slices is defined by
    # your `min_run` size.
    for i in range(0, n, min_run):
        insertion_sort(array, i, min((i + min_run - 1), n - 1))

    # Now you can start merging the sorted slices.
    # Start from `min_run`, doubling the size on
    # each iteration until you surpass the length of
    # the array.
    size = min_run
    while size < n:
        # Determine the arrays that will
        # be merged together
        for start in range(0, n, size * 2):
            # Compute the `midpoint` (where the first array ends
            # and the second starts) and the `endpoint` (where
            # the second array ends)
            midpoint = start + size - 1
            end = min((start + size * 2 - 1), (n-1))

            # Merge the two subarrays.
            # The `left` array should go from `start` to
            # `midpoint + 1`, while the `right` array should
            # go from `midpoint + 1` to `end + 1`.
            merged_array = merge(
                left=array[start:midpoint + 1],
                right=array[midpoint + 1:end + 1])

            # Finally, put the merged array back into
            # your array
            array[start:start + len(merged_array)] = merged_array

        # Each iteration should double the size of your arrays
        size *= 2

    return array

此修改後的實現添加了左右兩個參數,這些參數指示應對數組的哪一部分進行排序。這使Timsort算法可以對數組的一部分進行排序。修改功能而不是創建新功能意味着可以將其同時用於插入排序和Timsort。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章