数据结构与算法系列10--排序算法(归并、快排)

归并排序

思想:
归并排序的核心思想还是蛮简单的。如果要排序一个数组,我们先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起,这样整个数组就都有序了。


#归并排序
def merge_sort(a):
    n=len(a)
    merge_sort_between(a,0,n-1)


def merge_sort_between(a,low,high):
    #递归终止条件
    if low>=high:
        return

    #获取p到r之间的中间位置min
    min=(high+low)//2
    
    #分治递归排序,分成两个部分
    merge_sort_between(a,low,min)
    merge_sort_between(a,min+1,high)
    
    #将分治的两个数组合并,即将a[low...min]和a[min+1..high]合并
    merge(a,low,high,min)

#合并函数
def merge(a,low,high,min):
    #用两个游标 i 和 j,分别指向 A[low…min] 和 A[min+1…high] 的第一个元素
    i,j=low,min+1
    tmp=[]
    while i<=min and j<=high:
        if a[i]<=a[j]:
            tmp.append(a[i])
            i+=1
        else:
            tmp.append(a[j])
            j+=1

    #判断哪个子数组中有剩余的数据
    start = i if i <= min else j
    end = min if i <= min else high

    #将剩余的数据拷贝到临时数组tmp
    tmp.extend(a[start:end+1])

    #将tmp中的数组拷贝回a[low...high]
    a[low:high+1] = tmp



a1 = [3, 5, 6, 7, 8]
a2 = [2, 2, 2, 2]
a3 = [4, 3, 2, 1]
a4 = [5, -1, 9, 3, 7, 8, 3, -2, 9]
aa=[6,4,7,8,2,1,4,1]
merge_sort(aa)
print(aa)

第一,归并排序是稳定的排序算法吗?
归并排序是一个稳定的排序算法。
第二,归并排序的时间复杂度是多少?
归并排序的执行效率与要排序的原始数组的有序程度无关,所以其时间复杂度是非常稳定的,不管是最好情况、最坏情况,还是平均情况,时间复杂度都是O(nlogn)。
第三,归并排序是原地排序算法吗?空间复杂度是多少?
归并排序不是原地排序算法,这是因为归并排序的合并函数,在合并两个有序数组为一个有序数组时,需要借助额外的存储空间。它的空间复杂度是O(n)。

快速排序

思想:
如果要排序数组中下标从p到r之间的一组数据,我们选择p到r之间的任意一个数据作为pivot(分区点)。我们遍历p到r之间的数据,将小于pivot的放到左边,将大于pivot的放到右边,将pivot放到中间。经过这一步骤之后,数组p到r之间的数据就被分成了三个部分,前面p到q-1之间都是小于pivot的,中间是pivot,后面的q+1到r之间是大于pivot的。

from typing import List
import random

def quick_sort(a: List[int]):
    _quick_sort_between(a, 0, len(a)-1)

def _quick_sort_between(a: List[int], low: int, high: int):
    if low >= high: return
    # get a random position as the pivot
    k = random.randint(low, high)
    a[low], a[k] = a[k], a[low]

    m = _partition(a, low, high)   # 获取分区点
    _quick_sort_between(a, low, m-1)
    _quick_sort_between(a, m+1, high)

def _partition(a: List[int], low: int, high: int):
    pivot, j = a[low], low
    for i in range(low+1, high+1):
        if a[i] <= pivot:
            j += 1
            a[j], a[i] = a[i], a[j]  # swap
    a[low], a[j] = a[j], a[low]
    return j


if __name__ == "__main__":
    a1 = [3, 5, 6, 7, 8]
    a2 = [2, 2, 2, 2]
    a3 = [4, 3, 2, 1]
    a4 = [5, -1, 9, 3, 7, 8, 3, -2, 9]
    quick_sort(a1)
    print(a1)

第一,快速排序是稳定的排序算法吗?
快速排序并不是一个稳定的排序算法
第二,快速排序的时间复杂度是多少?
最好时间复杂度、平均时间复杂度:O(nlogn),最坏时间复杂度:O(n2)。
第三,快速排序是原地排序算法吗?

两种算法比较

归并排序算法是一种在任何情况下时间复杂度都比较稳定的排序算法,这也使它存在致命的缺点,即归并排序不是原地排序算法,空间复杂度比较高,是+O(n)。正因为此,它也没有快排应用广泛。
快速排序算法虽然最坏情况下的时间复杂度是O(n2),但是平均情况下时间复杂度都是O(nlogn)。不仅如此,快速排序算法时间复杂度退化到O(n2)+的概率非常小,我们可以通过合理地选择pivot来避免这种情况。

猜你喜欢

转载自blog.csdn.net/qq_34493908/article/details/83340149