[数据结构与算法] 排序算法


显卡拿去修理这段时间就复习下数据结构与算法吧. = =! 不然要失业了!

参考资料:
[1] 数据结构与算法 python语言描述 裘宗燕
[2] 维基百科 排序算法

排序

1. 冒泡排序

每一步都通过交换,把大的数后移。每一轮都有一个大的数字就位。

def bubble_sort(list):
    n = len(list)
    # 每一轮选出一个最大的数值的沉入数组的尾端
    for i in range(n-1):
        flag = True
        # 在第i轮,剩余数组的长度为n-i,由于两两比较,所以比较次数为剩余数组长度再减一。
        for j in range(n-i-1):  
            # 严格大于才会调序,保证算法的稳定性
            if list[j] > list[j+1]:
                list[j], list[j+1] = list[j+1], list[j]
                # 若发生了调整,则说明当前排序仍未完成
                flag = False
        if flag:
            return list
    return list
最坏时间复杂度 平均时间复杂度 最好时间复杂度 空间复杂度 稳定性 适应性
O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( n ) O(n) O(n) O ( 1 ) O(1) O(1)

2. 插入排序

从未排序的序列中选一个数值插入到已排序的序列中

def insert_sort(list):
    n = len(list)
    for i in range(n):
        temp = list[i]
        empty = i   # 取出数值,认为该位置为空
        # 空位置左侧的数字大于temp时,右移数字
        while empty > 0 and list[empty-1] > temp
                list[empty] = list[empty-1]
                # 数字后移后,空位置前移
                empty -= 1
                
        # 在空缺位置填入值
        list[empty] = temp
    return list
最坏时间复杂度 平均时间复杂度 最好时间复杂度 空间复杂度 稳定性 适应性
O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( n ) O(n) O(n) O ( 1 ) O(1) O(1)

3. 选择排序

每次从无序的序列中选择一个最小数值,放到已排序序列的末尾

def select_sort(list):
    n = len(list)
    for i in range(n):
        for j in range(i, n):
            if list[j] < list[i]:
                list[j], list[i] = list[i], list[j]
    return list
最坏时间复杂度 平均时间复杂度 最好时间复杂度 空间复杂度 稳定性 适应性
O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)

4. 希尔排序

希尔排序以不同的gap进行插入排序.

def shell_sort(list):
    n = len(list)
    gap = n // 2
    while gap > 0:
        for i in range(gap, n):
            temp = list[i]
            empty = i
            while empty > gap and list[empty - gap] > temp:
                list[empty] = list[empty - gap]
                empty -= gap
        gap = gap // 2
    return list
最坏时间复杂度 平均时间复杂度 最好时间复杂度 空间复杂度 稳定性 适应性
随步长而定 随步长而定 O ( n ) O(n) O(n) O ( 1 ) O(1) O(1)
步长序列 最坏时间复杂度
n / 2 i n/2^i n/2i O ( n 2 ) O(n^2) O(n2)
2 k 1 2^k-1 2k1 O ( n 3 / 2 ) O(n^{3/2}) O(n3/2)
2 i 3 j 2^i3^j 2i3j O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)

5. 归并排序

递归实现

def merge(left, right):
    result = []
    while left and right:
        if left[0] <= right[0]:
            result.append(left.pop(0))
        else:
            result.append(right.pop(0))
    if left:
        result += left
    if right:
        result += right
    
    return result

def merge_sort(list):
    if len(list) <= 1:
        return list
    
    mid = len(list) // 2
    left = list[:mid]
    right = list[mid:]

    left = merge_sort(left)
    right = merge_sort(right)

    return merge(left, right)

迭代实现

def merge(lfrom, lto, low, mid, high):
    i = low
    j = mid
    k = low
    while i < mid and j < high:
        if lfrom[i] <= lfrom[j]:
            lto[k] = lfrom[i]
            i += 1
        else:
            lto[k] = lfrom[j]
            j += 1
        k += 1

    while i < mid:
        lto[k] = lfrom[i]
        i += 1
        k += 1

    while j < high:
        lto[k] = lfrom[j]
        j += 1
        k += 1
    return lfrom, lto

def merge_pass(lfrom, llen, slen):
    i = 0
    lto = [None] * len(lfrom)
    while i + 2 * slen < llen:
        lfrom, lto = merge(lfrom, lto, i, i+slen, i+2*slen)
        i += 2 * slen
    # 剩余两段,第二段长度小鱼slen
    if i + slen < llen:
        lfrom, lto = merge(lfrom, lto, i, i+slen, llen)
    # 只剩余一段,直接复制
    else:
        while i < llen:
            lto[i] = lfrom[i]
            i+=1
    return lto

def merge_sort(lst):
    slen = 1
    llen = len(lst)
    while slen < llen:
        lst = merge_pass(lst, llen, slen)
        slen *= 2
    return lst

每经过一遍归并,有序子序列的长度将变成 2 k 2^k 2k,因此归并的遍数不会超过 l o g 2 n + 1 log_2n+1 log2n+1,而每遍归并时,比较次数为 O ( n ) O(n) O(n),因此时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

最坏时间复杂度 平均时间复杂度 最好时间复杂度 空间复杂度 稳定性 适应性
O ( n l o g n ) O(nlogn) O(nlogn) O ( n l o g n ) O(nlogn) O(nlogn) O ( n l o g n ) O(nlogn) O(nlogn) O ( n ) O(n) O(n)

6. 快速排序

def quick_rec(lst, b, e):
    if e <= b:
        return lst
    temp = lst[b]
    i = b
    j = e
    while i < j:
        # 严格加上i<j,否则会侵入已经分好的区域
        while i < j and lst[j] > temp:
            j -= 1
        if i < j:
            lst[i] = lst[j]
            i += 1
        while i < j and lst[i] < temp:
            i += 1
        if i < j:
            lst[j] = lst[i]
            j -= 1
    lst[i] = temp
    lst = quick_rec(lst, b, i-1)
    lst = quick_rec(lst, i+1, e)
    return lst

def quick_sort(lst):
    return quick_rec(lst, 0, len(lst)-1)
最坏时间复杂度 平均时间复杂度 最好时间复杂度 空间复杂度 稳定性 适应性
O ( n 2 ) O(n^2) O(n2) O ( n l o g n ) O(nlogn) O(nlogn) O ( n l o g n ) O(nlogn) O(nlogn) O ( 1 ) O(1) O(1)

7. 堆排序

构建一个最大堆,每次从最大堆中去除最大元素,放到数组的末尾,完成排序.

def heap_sort(lst):
    def sift_down(start, end):
        """ 从上到下调整节点,若父节点的值小于子节点,交换位置. """
        root = start
        child = 2 * root + 1
        while child < end:
            if child+1 < end and lst[child] < lst[child+1]:
                child += 1
            if lst[child] > lst[root]:
                lst[root], lst[child] = lst[child], lst[root]
                root, child = child, 2*child + 1
            else:
                break
    n = len(lst)
    # 建最大堆
    # len(lst)//2 -1 为最后一个树节点,其子节点都为叶节点
    for start in range(n//2-1, -1, -1):
        sift_down(start, n-1)
    
    # 从最大堆中取值
    for i in range(n-1, 0, -1):
        lst[i], lst[0] = lst[0], lst[i]
        sift_down(0, i-1)
    return lst
最坏时间复杂度 平均时间复杂度 最好时间复杂度 空间复杂度 稳定性 适应性
O ( n l o g n ) O(nlogn) O(nlogn) O ( n l o g n ) O(nlogn) O(nlogn) O ( n l o g n ) O(nlogn) O(nlogn) O ( 1 ) O(1) O(1)

8. 计数排序

当待排序序列中,不同数字的个数较少时(例如0-k之间的整数),计数排序是最快的方法.

def count_sort(lst):
    min_ = min(lst)
    max_ = max(lst)

    count = [0] * (max_ - min_ + 1)

    # 统计每一个数字出现的次数
    for num in lst:
        count[num-min_] += 1
    
    index = 0
    # 根据统计的结果,将数值回填到原来的list中
    for i, times in enumerate(count):
        for j in range(times):
            lst[index] = i + min_
            index += 1
    return lst
最坏时间复杂度 平均时间复杂度 最好时间复杂度 空间复杂度 稳定性 适应性
O ( n + k ) O(n+k) O(n+k) O ( n + k ) O(n+k) O(n+k) O ( n + k ) O(n+k) O(n+k) O ( n + k ) O(n+k) O(n+k)
全部评论

相关推荐

深夜书店vv:腾讯是这样的,去年很多走廊都加桌子当工区
点赞 评论 收藏
分享
仁者伍敌:难怪小公司那么挑剔,让你们这些大佬把位置拿了
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务