Problema de partición [Python], bandera holandesa, cola rápida clásica, cola rápida aleatoria

Este artículo se divide principalmente en tres partes:

  1. Problemas básicos de partición

  2. Problema de la bandera holandesa

  3. Clasificación rápida clásica y clasificación rápida aleatoria


1. Problema de partición básica

Dado un arreglo arr y un número num, coloque el número menor o igual a num a la izquierda de la matriz, y el número mayor que num a la derecha de la matriz, lo que requiere complejidad de espacio adicional O (1), complejidad de tiempo O (N )

# 1. 快排基础 partition思想
#    给定一个数组arr,和一个数num,请把小于等于num的数放在数组的左边,大于num的数放在数组的右边
#    要求额外空间复杂度O(1),时间复杂度O(N)
import numpy as np 
arr = list(np.random.randint(10, size=6))
num = int(np.random.randint(10,size=1))

def partition(arr, num):
    """划分数组, 时间复杂度O(n),空间复杂度O(1)"""
    idx_left = 0
    idx_right = len(arr)
 
    while  idx_left < idx_right : # 终止条件要考虑清楚
        if arr[idx_left] <= num:
            idx_left += 1
            print('left', arr, idx_left, idx_right)

        else:
            idx_right -= 1
            arr[idx_left], arr[idx_right] = arr[idx_right], arr[idx_left]
            print('right', arr, idx_left, idx_right)
      
    return arr    

print(arr)
print(num)
res = partition(arr, num)
print('res', res)

2. La bandera holandesa

# 2. 荷兰国旗问题
# 给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。
# 要求额外空间复杂度O(1),时间复杂度O(N)
def helan_flag(arr, num):
    """划分数组, 时间复杂度O(n),空间复杂度O(1)"""
    # 设立三个辅助index
    idx_left = -1
    idx_right = len(arr)
    idx_current = 0
    while idx_current < idx_right: #注意终止条件

        if arr[idx_current] < num:
            idx_left += 1
            arr[idx_left], arr[idx_current] = arr[idx_current], arr[idx_left]
            idx_current += 1

        elif arr[idx_current] > num:
            idx_right -= 1
            arr[idx_current], arr[idx_right] = arr[idx_right], arr[idx_current]

        else:
            idx_current += 1 
    return arr

# test
res = helan_flag([3,5,5,5,7,8,9,1,2,3,5,5,5], 5)
print('res', res) 

3. Fila rápida clásica y fila rápida aleatoria

# 3. 快排
# 3.1 经典快排 将arr最后一位数x作为划分值,分成2块,小于等于x的放左边,大于x的放右边
# 3.2 改进快排 将arr最后一位数作为划分值, 结合荷兰国旗问题,分成3块, 小于x放左边,等于x放中间,大于x放右边
#     why 改进后的快排比经典快排更好? (经典快排一次只搞定了一个位置的数,即x,改进的快排一次搞定了所有等于x的数)

def partition(arr, left, right):
    if len(arr) <= 1:
        return arr
    num = arr[-1]
    idx_left = left - 1
    idx_right = right 
    idx_current = left
    while idx_current < idx_right:
        if arr[idx_current] < num:
            idx_left += 1
            arr[idx_left], arr[idx_current] = arr[idx_current], arr[idx_left]
            idx_current += 1
        elif arr[idx_current] > num:
            idx_right -= 1
            arr[idx_right], arr[idx_current] = arr[idx_current], arr[idx_right]
        else:
            idx_current += 1
    #  把最后一位数划分值 放到中间
    arr[-1], arr[idx_right] = arr[idx_right], arr[-1]
    idx_right += 1
    
    return idx_left, idx_right
 

def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    left, right = partition(arr, 0, len(arr)-1)
    mid = arr[left+1:right]
    return quick_sort(arr[:left+1]) + mid + quick_sort(arr[right:])
    

import numpy as np 
flag = True
for i in range(1000):
    arr = list(np.random.randint(100, size=50))
    res1 = quick_sort(arr)
    arr.sort()
    if arr != res1:
        flag = False 
        print('res1', res1)
        print('arr', arr)
        break
print(flag)

# 3.3 随机快排 时间复杂度O( N*logN )
# 改进快排还可以进一步改进为随机快排,总是固定拿arr最后一位数当作划分值可能造成划分的子问题不是等规模的,与待排序的数据状况有关
# 例如,原数组是升序排列的,[1, 2, 3, 4, 5, 6, 7], 每次partition只搞定一个数,快排退化成O(n^2)
# 想绕开数据原始的数据状况一般有两种方式: 随机选取  &  哈希

import numpy as np 

def partition(arr, left, right):
    if len(arr) <= 1:
        return arr
    ##与普通快排的区别之处,随机选择一个位置的数和arr最后一个位置的数进行交换
    idx_random = int(np.random.randint(len(arr), size=1))
    arr[idx_random], arr[-1] = arr[-1], arr[idx_random]
    ############################################## 接下来和3.2一样
    num = arr[-1]
    idx_left = left - 1
    idx_right = right 
    idx_current = left
    while idx_current < idx_right:
        if arr[idx_current] < num:
            idx_left += 1
            arr[idx_left], arr[idx_current] = arr[idx_current], arr[idx_left]
            idx_current += 1
        elif arr[idx_current] > num:
            idx_right -= 1
            arr[idx_right], arr[idx_current] = arr[idx_current], arr[idx_right]
        else:
            idx_current += 1
    #  把最后一位数划分值 放到中间
    arr[-1], arr[idx_right] = arr[idx_right], arr[-1]
    idx_right += 1
    
    return idx_left, idx_right
 
def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    left, right = partition(arr, 0, len(arr)-1)
    mid = arr[left+1:right]
    return quick_sort(arr[:left+1]) + mid + quick_sort(arr[right:])
# test
flag = True
for i in range(1000):
    arr = list(np.random.randint(100, size=50))
    res1 = quick_sort(arr)
    arr.sort()
    if arr != res1:
        flag = False 
        print('res1', res1)
        print('arr', arr)
        break
print(flag)

 

Publicado 26 artículos originales · ganó 13 · vistas 7292

Supongo que te gusta

Origin blog.csdn.net/original_recipe/article/details/89360894
Recomendado
Clasificación