数据结构学习——09—排序算法(快速排序、归并排序、常见排序算法比较)

一、快速排序(quick sort)
快速排序,又称划分交换排序(partition-exchange sort),通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

排序步骤为:
1、从数列中挑出一个元素,称为"基准"(pivot)(初始一般为第一个元素)
2、重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
3、递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
在这里插入图片描述
快速排序代码实现:

# -*- encoding: utf-8 -*-
"""
@File    : quick_sort.py
@Time    : 2019/11/21 9:53
@Author  : chen

"""

# 快速排序
def quick_sort(li, start, end):
    # low = 0
    # high = len(li) - 1        # 队列最后元素的下标   需要-1
    low = start
    high = end
    
    mid = li[low]             # 排序基准初始设定
    
    # if start >= end:          # 递归的退出条件   通过low、high改变,再递归修改了start和end
    if low >= high:             # 递归的退出条件   两种条件相同意思
        return
    
    while low != high:                            # 也可以使用low < high判断条件    low==high的时候循环退出
        while low < high and li[high] >= mid:     # 当游标high所指的元素值 >= 基准值,不做交换,high的游标往前移动
            high -= 1
        
        # if li[high] < mid:                       # 当游标high所指的元素值 < 基准值,将high所指的值赋值给low游标
        li[low] = li[high]
        
        while low < high and li[low] < mid:        # 当游标low所指的元素值 < 基准值,不做交换,low 的游标往前移动
            low += 1
        
        # if li[low] > mid:                        # 当游标low所指的元素值 > 基准值,将low所指的值赋值给high游标
        li[high] = li[low]
        

    li[low] = mid                                  # low==high的时候循环退出执行这句,此时的low和high已经循环完整个列表,处于同一位置,此位置就是mid应该放入的位置
    
    # 对前面的元素进行快速排序,比mid小的部分
    quick_sort(li, start, low-1)
    
    # 对后面的元素进行快速排序,比mid大的部分
    quick_sort(li, low+1, end)
    

if __name__ == '__main__':
    li = [3, 4, 57, 32, 13, 46, 21, 55, 77]
    quick_sort(li, 0, len(li)-1)
    print(li)

快速排序不是稳定的排序算法,不能保证相同元素的顺序不变。它的最坏情况时间复杂度是O(n^2).

二、归并排序
归并排序的思想就是先递归分解数组,再合并数组。

将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。

# -*- encoding: utf-8 -*-
"""
@File    : merge_sort.py
@Time    : 2019/11/21 17:28
@Author  : chen

"""


'''
归并排序
将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。
然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。
'''

# 归并排序
def merge_sort(li):
    '''
    :param li:
    :return:   排序列表
    '''
    # 停止拆分条件    拆成单独的一个元素
    if len(li) <= 1:
        return li
    
    # 二分分解
    mid_index = len(li) // 2
    left_li = merge_sort(li[:mid_index])       # 被拆分的数列的左边部分
    right_li = merge_sort(li[mid_index:])      # 被拆分的数列的左边部分      注意:的位置
    
    left_index = 0            # 左边数列游标
    right_index = 0           # 右边数列游标
    result = []               # 把排序好的添加进这个list
    
    # 空list的情况
    
    while left_index < len(left_li) and right_index < len(right_li):        # 循环条件:左右游标要小于被拆分的数列长度
        if left_li[left_index] < right_li[right_index]:                     # 比较游标所指的两个元素大小
            result.append(left_li[left_index])                              # 添加进新的list
            left_index += 1                                                 # 左游标继续移动
        else:
            result.append(right_li[right_index])                            # 右游标的值最小
            right_index += 1                                                # 右游标继续移动
    
    print("左边拆分数列:", left_li)                                          # 左边排序的list
    print("右边拆分数列:", right_li)                                         # 右边排序的list
    print("排序数列:", result)
    
    result += left_li[left_index:]                            # 当游标遍历完拆分的list,合并左右列表
    result += right_li[right_index:]
    
    return result                                             # 排序完成的列表
    



if __name__ == '__main__':
    li = [3, 4, 57, 32, 13, 46, 21, 55, 77]
    m = merge_sort(li)
    print("最后排序完成列表:", m)




三、常见排序算法效率比较:

插入排序、希尔排序、快速排序

递归、冒泡、选择排序
在这里插入图片描述
辅助空间:辅助空间是完成算法所需的额外空间,O(1)是最理想的,这样的算法其辅助空间不依赖于问题的规模,换句话说这样的算法是稳定的。同时也有O(n),O(logn)~O(n)

发布了50 篇原创文章 · 获赞 9 · 访问量 2097

猜你喜欢

转载自blog.csdn.net/weixin_42118531/article/details/103186504