[Python] partition problem, Dutch flag, classic quick queue, random quick queue

This article is mainly divided into three parts:

  1. Basic partition issues

  2. Dutch flag issue

  3. Classic Quick Sort & Random Quick Sort


1. Basic partition problem

Given an array arr and a number num, please place the number less than or equal to num on the left of the array, and the number greater than num on the right of the array, requiring extra space complexity O (1), time complexity 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. The Dutch flag

# 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. Classic Quick Row & Random Quick Row

# 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)

 

Published 26 original articles · won 13 · views 7292

Guess you like

Origin blog.csdn.net/original_recipe/article/details/89360894