排序算法

Posted wemo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法相关的知识,希望对你有一定的参考价值。

排序算法的稳定性:让原本相等的键值维持的纪录维持相对次序

冒泡排序(BUbble Sort)

从头往后走,每次比较相邻的两个数字,一次循环将最大(最小)的数字放在最后,经过n-1次冒泡完成排序。

冒泡:每次将最大的值往后移到相应的位置(第一次最大,第二次次大,依次往后)

#关键代码
for i in range(n-1):
    flag = 0
    for j in range(n-1-j):
        if bubble[j] > bubble[j+1]:
            bubble[j], bubble[j+1] = bubble[j+1], bubble[j]
            flag = 1
    if flag == 0: #该序列不需要进行排序
        return bubble
            

时间复杂度:O(n2)

稳定性:稳定

选择排序

从未排序的序列中选择一个次小的让前面去放

#关键代码
n = len(alist)
for j in range(n-1):
    min_index = j
    for i in range(j+1, n):
        if alist[min_index] > alist[i]:
            min_index = i
    alist[j], alist[min_index] = alist[min_index], alist[j]
    

时间复杂度:O(n2)

稳定性:不稳定

插入算法

把后面序列的数字插入到前面序列合适的位置

#关键代码
for i in range(1, n):
    while i > 0:
        if alist[i] < alist[i-1]:
            alist[i], alist[i-1] = alist[i-1], alist[i]
            i -= 1
        else:
            break
            

时间复杂度:O(n2)

稳定性:稳定

希尔排序

对插入算法的改进。其基本思想是:先比较距离远的元素,而不是像简单交换排序算法那样先比较相邻的元素,这样可以快速减少大量的无序情况,从而减轻后续的工作。被比较的元素之间的距离逐步减少,直到减少为1,这时的排序变成了相邻元素的互换。

#关键代码实现
def shell_sort(alist):
"""希尔排序"""
n = len(alist)
gap = n//2

while gap > 0:
    for j in range(gap, n):
        i = j
        while i > 0:
            if alist[i] < alist[i-gap]:
                alist[i], alist[i-gap] = alist[i-gap], alist[i]
                i -= gap
            else:
                break
    gap //= 2
    

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

稳定性:不稳定

快速排序

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

#关键代码
def quick_sort(alist, first, last):
    if first == last:
        return 
    mid_value = alist[0]
    low = firsst
    high = last
    
    while low < high:
        #high左移
        while low < high and alist[high] >= mid_value:
            high -= 1
        alist[low] = alist[high]
        
        while low < high and alist[low] < mid_value:
            low += 1
        alist[high] = alist[low]
    #从循环退出,low==high    
    alist[low] = mid_value
    
    #对low左边进行快速排序
    quick_sort(alist, first, low-1)
    #对low右边的列表进行快速排序
    quick_sort(alist, low+1, last)
    

最优时间复杂度: O(nlogn) (经过多少次对半折分可以拆到1,nlog2n)

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

稳定性:不稳定

归并算法

基本思想:先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,即二路归并

#关键代码
def merge_sort(alist):
    """归并排序"""
    n = len(alist)
    if n <= 1
        return alist
    mid == n//2
        
    # left采用归并排序后形成的有序的新的列表
    left_li = merge_sort(alist[:mid])
    
    # right采用归并排序后形成的有序的新的列表
    right_li = merge_sort(alist[mid:])
    
    left_pointer, right_pointer = 0, 0
    result = []
    
    while left_pointer < len(left_li) and right_pointer < len(right_li):
        if left_li[left_pointer] <= right_li[right_pointer]:
            result.append(left_li[left_pointer])
            left_pointer += 1
        elif: 
        result.append(right_li[right_pointer])
        right_pointer += 1
    
    result += left_li[left_pointer:]
    result += right_li[right_pointer:]
    return result

最优时间复杂度:O(nlogn) (理解:纵向是logn级序列拆分,横向进行n次比较)

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

稳定性:稳定

时间上是最小的,但是空间上,需要额外的开销,前面的算法是在原有的列表上进行排序的。

搜索算法——二分查找

二分查找,又称为折半查找。查找对象:有序的顺序表。

def binary_search(alist, item):
    """二分查找"""
    n = len(alist)
    if n > 0:
        mid = n//2
        if alist[mid] == item:
            return True
        elif item < alist[mid]:
            return binary_search(alist[:mid], item)
        else:
            return binary_search(alist[mid:], item)
    return False
    
# 非递归
def binary_search(alist, item):
    """二分查找,非递归"""
    n = len(alist)
    first = 0
    last = n-1
    while first <= last:
        mid = (first + last)//2
        if alist[mid] == item:
            return True
        elif alist[mid] > item:
            last = mid -1
        else:
            first = mid + 1
    return False
    

最坏时间复杂度:O(logn) (普通遍历查找时间复杂度是O(n))

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

以上是关于排序算法的主要内容,如果未能解决你的问题,请参考以下文章

算法排序之堆排序

快速排序-递归实现

从搜索文档中查找最小片段的算法?

在第6731次释放指针后双重免费或损坏

TimSort算法分析

以下代码片段的算法复杂度