数据结构与算法(python):归并排序和快速排序算法及分析

参考自 MOOC数据结构与算法Python版

一、归并排序 Merge Sort

1.1 算法思路

归并排序是递归算法, 思路是将数据表持续分裂为两半, 对两半分别进行归并排序
【步骤】
递归的基本结束条件是:数据表仅有1个数据项,自然是排好序的;

  1. 缩小规模:将数据表分裂为相等的两半,规模减为原来的二分之一;
  2. 调用自身:将两半分别调用自身排序,然后将分
    别排好序的两半进行归并,得到排好序的数据表

在这里插入图片描述

1.2 代码及算法分析

【代码1】

def mergeSort(alist):
    if len(alist)>1: #基本结束条件
        mid = len(alist)//2
        lefthalf = alist[:mid]
        righthalf = alist[mid:]
        #递归拆分
        mergeSort(lefthalf) 
        mergeSort(righthalf)
        #比较合并
        i = j = k = 0
        while i<len(lefthalf) and j<len(righthalf):
        	#从小到大归并结果
            if lefthalf[i] < righthalf[j]: 
                alist[k] = lefthalf[i]
                i += 1
            else:
                alist[k] = righthalf[j]
                j += 1
            k += 1
        #归并左半部剩余项
        while i<len(lefthalf):
            alist[k] = lefthalf[i]
            i += 1
            k += 1
        #归并右半部剩余项
        while j<len(righthalf):
            alist[k] = righthalf[j]
            j += 1
            k += 1
alist = [1, 43, 35, 21, 76, 12, 89, 22]      
mergeSort(alist)
print(alist)   

【代码2】更加Pythonic(实现存在问题,找时间更改)

def mergeSort2(lst):
    #递归结束条件
    if len(lst)<= 1:
        return lst
    #分解问题,并递归调用
    middle = len(lst)//2
    left = mergeSort2(lst[:middle])
    right = mergeSort2(lst[middle:])
    #合并左右半部,完成排序
    merged =[]
    while left and right: #只要左右半部都有数据
        if left[0] <= right[0]:
            merged.append(left.pop(0))
        else:
            merged.append(right.pop(0))
    merged.extend(right if right else left)
    return merged
  
alist = [1, 43, 35, 21, 76, 12, 89, 22]      
mergeSort2(alist)
print(alist)           

【算法分析】
将归并排序分为两个过程来分析: 分裂和归并;
分裂的过程, 借鉴二分查找中的分析结果, 是对数复杂度, 时间复杂度为是 O ( l o g n ) O(log n) O(logn)
归并的过程, 相对于分裂的每个部分, 其所有数据项都会被比较和放置一次, 所以是线性复杂度, 其时间复杂度是 O ( n ) O(n) O(n)
综合考虑,每次分裂的部分都进行一次O(n)的数据项归并,总的时间复杂度是 O ( n l o g n ) O(nlog n) O(nlogn)

二、快速排序 Quick Sort

2.1 算法思路

快速排序的思路是依据一个“中值”数据项来把数据表分为两半:小于中值的一半和大于中值的一半, 然后每部分分别进行快速排序(递归)。
中位数”可使两个部分的数据量相等,但寻找中位数存在开销,因此,只能随便找一个数充当中值,如第一个数。
【递归三要素】:

  1. 基本结束条件:数据表中仅有1个数据项,自然是排好序的。
  2. 缩小规模:根据“中值”,将数据表分为两半,最好情况是相等规模的两半。
  3. 调用自身:将两半分别调用自身进行排序

如取最后一个数为中值,设置头尾两个指针,分别往中间移动,移动的过程中跟中值进行比较,当满足尾指针指向的数比中值小且头指针指向的数比中值大,则交换两数位置,目的是为了让小数在前,大数在后。
在这里插入图片描述

2.2 代码及算法分析

【代码】:

def partition(alist, first, last):
    pivotvalue = alist[first]  #选定中值
    
    leftmark = first + 1   #左右标初值
    rightmark = last
    
    done = False
    while not done:
        #左标向右移动
        while leftmark <= rightmark and alist[leftmark] <= pivotvalue:  
            leftmark += 1
        #右标向左移动
        while rightmark >= leftmark and alist[rightmark] >= pivotvalue: 
            rightmark -= 1
        if rightmark < leftmark:  #两标交错就结束移动
            done = True
        else:           #左右标的值交换
            temp = alist[leftmark]  
            alist[leftmark] = alist[rightmark]
            alist[rightmark] = temp
    #中值就位
    temp = alist[first]
    alist[first] = alist[rightmark]
    alist[rightmark] = temp
    return rightmark  #中值点,也就是分裂点

def quickSort(alist):
    quickSortHelper(alist, 0, len(alist)-1)

def quickSortHelper(alist, first, last):
    if first < last:   #基本结束条件
        splitpoint = partition(alist, first, last)  #分裂
        quickSortHelper(alist, first, splitpoint-1)  #递归调用
        quickSortHelper(alist, splitpoint+1, last)    #递归调用
alist = [43, 23, 76, 12, 45, 89, 22, 9]
quickSort(alist)
print(alist)        

【算法分析】:
快速排序过程分为两部分: 分裂和移动
如果分裂总能把数据表分为相等的两部分,那么就是 O ( l o g n ) O(log n) O(logn)的复杂度;
而移动需要将每项都与中值进行比对,还是 O ( n ) O(n) O(n)
综合起来就是 O ( n l o g n ) O(nlog n) O(nlogn)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值