常见的几种排序算法

一:冒泡排序

基本思想:从头开始比较两个数大小,较大的数下沉,较小的数冒起来,如果第二个数小,就交换位置,这样每循环一次最大的数都会跑到最后

最坏时间复杂度:O(n2)

最优时间复杂度:O(n)  表示遍历一次发现没有可以交换的元素,即无需排序

稳定性:稳定

代码实现

def bubble_sort(arr):
    for i in range(len(arr) - 1):
        count = 0
        for j in range(len(arr) - 1 - i):
            if arr[j] > arr[j + 1]:
                arr[j + 1], arr[j] = arr[j], arr[j + 1]
                count += 1
        # 对算法的优化,当某次循环后,列表结构并没发生变化,说明列表已排序完成,无需进行后续的循环冒泡操作
        if count == 0:
            return arr
    return arr

 

二:选择排序

基本思想:将数组理解为两部分即已排序部分和未排序部分,每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到全部待排序的数据元素排完。

最坏时间复杂度:O(n2)

最优时间复杂度:O(n2)

稳定性:不稳定

代码实现

def select_sort(arr):
    for i in range(len(arr) - 1):
        min = i
        for j in range(i+1, len(arr)):
            if arr[min] > arr[j]:
                min = j
     # 遍历所有未排序元素,将其中最小的数据和已排序部分的最后一个元素进行交换 arr[i], arr[min]
= arr[min], arr[i] return arr

 

 

三:插入排序

基本思想:将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序

最坏时间复杂度:O(n2)

最优时间复杂度:O(n)

稳定性:稳定

代码实现:

def insert_sort(arr):
    # 从列表的第二个位置开始向前插入
    for i in range(1,len(arr)):
        for j in range(i,0,-1):
            # 从第i个元素开始向前进行比较,如果小于前面那个数就交换位置
            if arr[j]<arr[j-1]:
                arr[j],arr[j-1]=arr[j-1],arr[j]
            # 对算法的优化 一旦后一个元素比前一个元素大 那么后续的比较就没有意义了
            else:
                break
    return arr

 

 

四:希尔排序

基本思想:希尔排序是把列表按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的元素越来越多,当增量减至1时,整个列表恰被分成一组,算法便终止

最坏时间复杂度:O(n2)

最优时间复杂度:O(n1.3)

稳定性:不稳定

代码实现:

def shell_sort(arr):
    # 规定增量
    gap=len(arr)//2
    while gap>0:
        for i in range(gap,len(arr)):
            # 按增量分好的的组进行插入排序,同组中每个元素的index值相差gap
            while i-gap>=0:
                if arr[i]<arr[i-gap]:
                    arr[i],arr[i-gap]=arr[i-gap],arr[i]
                    i=i-gap
                else:
                    break
        # 增量减半
        gap=gap//2
    return arr

 

 

五:快速排序

基本思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

最坏时间复杂度:O(n2)

最优时间复杂度:O(nlogn)

稳定性:不稳定

代码实现:

def quick_sort(arr, first, last):
    """
    使用递归进行快速排序
    :param arr: 要进行排序的列表
    :param first: 列表的起始点(例 快排初始列表传入的起始点为 0  终止点为len(arr)-1 )
    :param last: 列表的终止点
    """
    # 递归的结束条件
    if first >= last:
        return
    # 选取笔杆值 比笔杆值大的都放在笔杆值右边 比笔杆值小的都放在笔杆值左边
    mid_value = arr[first]
    low = first
    high = last
    while low < high:
        while low < high and arr[high] >= mid_value:
            high -= 1
        arr[low] = arr[high]
        while low < high and arr[low] < mid_value:
            low += 1
        arr[high] = arr[low]
    arr[low] = mid_value 

    # 递归调用 以笔杆值为分隔传入要排序的某段列表
    quick_sort(arr, first, low - 1)
    quick_sort(arr, low + 1, last)

 

 

六:归并排序

基本思想:将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序

最坏时间复杂度:O(nlogn)

最优时间复杂度:O(nlogn)

稳定性:稳定

特点:时间复杂度低,但是最终返回的是一个新的列表,需要开辟新的内存空间去保存,而上述其他排序算法都是在原列表上进行操作,并不涉及到空间上的改变

代码实现:

def merge_sort(arr):
    n = len(arr)
    # 拆分列表的递归终止条件(把原列表拆成只有单个元素的列表)
    if n <= 1:
        return arr
    mid = n // 2
    # 归并排序后形成的有序的新列表
    left_arr = merge_sort(arr[:mid])
    # 归并排序后形成的有序的新列表
    right_arr = merge_sort(arr[mid:])

    left_pointer, right_pointer = 0, 0
    # 两个有序列表合并成一个有序的列表
    result = []
    while left_pointer < len(left_arr) and right_pointer < len(right_arr):
        if left_arr[left_pointer] <= right_arr[right_pointer]:
            result.append(left_arr[left_pointer])
            left_pointer += 1
        else:
            result.append(right_arr[right_pointer])
            right_pointer += 1
    result += left_arr[left_pointer:]
    result += right_arr[right_pointer:]
    return result

 

posted on 2018-12-28 20:46  叶杨森  阅读(230)  评论(0)    收藏  举报