python实现的5种排序算法

388 阅读3分钟

冒泡排序

思路

依次比较相邻的2个元素,把大的往后放,直至把最大值放到最后。

import unittest

def BubbleSort(arr):
    length = len(arr)
    # i 当前找到的最大元素个数,从0到n
    for i in range(length):
        # 任务A的具体实现,每次循环的结束点都是比较当前未排序元素的倒数第二个和最后一个
        for j in range(length-i-1):
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
    return arr

#编写unittest单元测试用例来进行验证
class SortTestCase(unittest.TestCase):
    def test_bubble_sort(self):
        test_data_1 = [8,7,0,9,4,5,2]
        test_data_2 = [8,8,6,5]
        copy_of_data_1 = test_data_1[:]
        copy_of_data_2 = test_data_2[:]

        BubbleSort(test_data_1)
        BubbleSort(test_data_2)

        copy_of_data_1.sort()
        copy_of_data_2.sort()

        self.assertEqual(test_data_1, copy_of_data_1)
        self.assertEqual(test_data_2, copy_of_data_2)

if __name__ == '__main__':
    unittest.main()
  • 时间复杂度:O(n^2)

选择排序

思路

依次跟未排序的最后一个元素进行比较大小,如果比它大,则交换。

def selection_sort(arr):
    length = len(arr)
    for i in range(length-1, 0, -1):
        for j in range(i):
            if arr[j] > arr[i]:
                arr[j], arr[i] = arr[i], arr[j]
    return arr
  • 时间复杂度:O(n^2)

插入排序

思路

从位置1开始,将元素跟已排序依次进行比较,插入到正确的位置。(就跟打扑克一样,拿到牌插入到正确的位置)

def InsertionSort(arr):
    length = len(arr)
    # 从位置1开始从左往右遍历,假设位置0上的元素是排序好的
    i = 1
    while i < length:
        # j代表当前已排序的数字的结束位置
        j = i
        while j > 0:
            if arr[j -1] > arr[j]:
                arr[j-1], arr[j] = arr[j], arr[j-1]
            j = j - 1
        i = i + 1
  • 时间复杂度:O(n^2)

快速排序

思路

选择一个元素为标准,将比它小的元素都挪到它前面,比它大的元素都挪到它后面。然后将其所在位置返回。然后分别对前后两部分进行递归。

def quick_sort(arr, l, r):
    if l < r:
        q = partition(arr, l, r)
        quick_sort(arr, l, q-1)
        quick_sort(arr,q+1, r)


# 找到中间点i,并把比arr[i]都挪到i的左边 
def partition(arr, l, r):
    x = arr[r]
    i = l - 1
    for j in range(l, r):
        if arr[j] <= x:
            i = i+1
            arr[i], arr[j] = arr[j], arr[i]
    arr[i+1], arr[r] = arr[r], arr[i+1]
    return i + 1
  • 平均时间复杂度O(nlgn)
  • 最坏时间复杂度O(n^2)

归并排序

思路

先把数组从中间分成左右两份,然后对两部分分别排序,再讲排好序的两部分合并在一起,这样整个数组都有序了。 归并排序的执行效率与要排序的原始数组的有序程度无关,所以其时间复杂度是非常稳定的,不管是最好情况、最坏情况或平均情况,时间复杂度都是O(nlogn)。

def mergerSort(arr, l ,r):
    if l < r:
        m = int((l+(r-1))/2)
        mergerSort(arr, l, m)
        mergerSort(arr, m+1, r)
        merge(arr, l, m, r)

# 将2个排好序的部分合并
def merge(arr, l, m, r):
    n1 = m-l+1
    n2 = r-m

    # 创建临时数据
    L = [0]*n1
    R = [0]*n2

    # 拷贝数据到临时数组,可以保证值相同的元素,在合并的前后先后顺序不变。保障了稳定性
    for i in range(0, n1):
        L[i] = arr[l+i]

    for j in range(0, n2):
        R[j] = arr[m+1+j]

    # 归并临时数组到arr[l..r]
    i = 0 # 初始第一个子数组的索引
    j = 0 # 初始第二个子数组的索引
    k = l # 初始归并子数组的索引

    while i < n1 and j < n2:
        if L[i] <= R[j]:
            arr[k] = L[i]
            i += 1
        else:
            arr[k] = R[j]
            j += 1
        k += 1

    while i < n1:
        arr[k] = L[i]
        i += 1
        k += 1
        
    while j < n2:
        arr[k] = R[j]
        j += 1
        k += 1
  • 平均时间复杂度O(nlgn)
  • 最坏时间复杂度O(nlgn)