Python 排序算法(二)荷兰国旗问题、随机快排、堆排序

问题1:荷兰国旗问题

给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。

要求额外空间复杂度O(1),时间复杂度O(N)

import random

def netherlands_flag(arr, l, r, num):
    less = l - 1  # 便于理解
    more = r + 1
    while l < more:
        if arr[l] < num:
            less += 1
            arr[less], arr[l] = arr[l], arr[less]
            l += 1
        elif arr[l] > num: # 拿过来的数据待定,则不能l+=1
            more -= 1
            arr[more], arr[l] = arr[l], arr[more]
        else:
            l += 1
    return (less+1, more-1)  # 返回num的区域下标

def generate_arr(size):
    arr = []
    for i in range(size):
        arr.append(int(random.random() * 3)) # [0-2]
    return arr

arr = generate_arr(10)
num_index = netherlands_flag(arr, l=0, r=len(arr) - 1, num=1)
print(arr)
print(num_index)

二、随机快排细节和复杂度分析

  • partition 不均问题,或者当为有序数组时,经典快排容易出现 O(n^2)。经典快排空间复杂度最坏为 O(N),最好为 O(logN)
  • 随机快排的 (长期期望) 时间复杂度为 O(N*logN),(最常用的排序算法,实现简单,常数项少, 空间复杂度低),额外 (长期期望) 空间复杂度 O(logN)
  • 工程中一般不会使用递归函数,递归都能改成非递归。系统压栈会有过多无用常数项
import random

def quick_sort(arr, l, r):
    if l < r:
        # 随机获取[l:r]某个数, 这里l不能少,不然递归出问题
        r_num = l + int(random.random() * (r - l + 1))  
        arr[r_num], arr[r] = arr[r], arr[r_num]
        p = netherlands_flag(arr, l, r)  # p为中位数的前后位置元祖
        quick_sort(arr, l, p[0] -1)
        quick_sort(arr, p[1] + 1, r)

def netherlands_flag(arr, l, r):
    less = l - 1
    more = r  # 这里r为中位数,不参与比较,最后需要置换
    while l < more:
        if arr[l] < arr[r]:
            less += 1
            arr[less], arr[l] = arr[l], arr[less]
            l += 1
        elif arr[l] > arr[r]:
            more -= 1
            arr[more], arr[l] = arr[l], arr[more]
        else:
            l += 1
    arr[more], arr[r] = arr[r], arr[more]
    return [less+1, more]


def generate_arr(size):
    arr = []
    for i in range(size):
        arr.append(int(random.random() * 10)) # [0-10]
    return arr

arr = generate_arr(10)
print(f'old arr: {arr}')
quick_sort(arr, l=0, r=len(arr) - 1)  # [3, 6, 5, 8, 4]
print(f'sort arr: {arr}')

堆排序的细节和复杂度分析

完全二叉树(堆 --> 完全二叉树),叶节点概念

i节点:左 2i + 1,右 2i + 2,父 int((i - 1)/2),int() 保证出现 -1/2 为0

  • 大根堆:完全二叉树中每一颗头节点都为最大值
  • 小根堆:完全二叉树中子节点为最小值
  • heapinsert:新的节点加入,重新生成大跟堆
  • heapify:节点发送变化,重新生成大根堆

流数据求中位数:准备大根堆和小根堆,保证两边数据相差不超过1,中位数就是两个表头之一。

堆排序Code

# 时间复杂度O(N*logN),额外空间复杂度O(1)
def code_02_heap_sort():
    def heap_sort(arr):
        if arr == [] or len(arr) <2:
            return arr
        for i in range(len(arr)):
            heap_insert(arr, i)

        size = len(arr) - 1
        arr[0], arr[size] = arr[size], arr[0]
        while size > 0:
            heapify(arr, 0, size)
            size -= 1
            arr[0], arr[size] = arr[size], arr[0]


    def heap_insert(arr, index):
        parent_node = int((index - 1) / 2)
        while arr[index] > arr[parent_node]:
            arr[index], arr[parent_node] = arr[parent_node], arr[index]
            index = parent_node
            parent_node = int((index - 1) / 2)

    def heapify(arr, index, size):
        left_node = index*2 + 1
        while left_node < size:
            largest = left_node+1 if left_node + 1 < size and arr[left_node+1] > arr[left_node] else left_node
            largest = largest if arr[largest] > arr[index] else index
            if largest == index:
                break
            arr[index], arr[largest] = arr[largest], arr[index]
            index = largest
            left_node = index*2 + 1

    arr = [3,1,2,6,0,4]  # 这里可以使用对数器,解决样本问题
    heap_sort(arr)
    print(arr)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值