快速排序
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/1/6 11:14
# @Author : Lili
# @File : 快速排序.py
# @Description : 分治策略实现快速排序, 可以通过改递归为循环或者随机取中间值的方法来优化
def partition(a: list, p: int, r: int) -> int:
"""
对a[p:r]进行划分, 小于a[p]的元素交换到左边区域
:param a: 待划分列表
:param p: 起始位置
:param r: 结束位置
:return: 划分中间值的位置
"""
i = p
j = r + 1
x = a[p]
# 将小于x的元素交换到左边区域
while True:
# for循环有点问题
# for i in range(i+1, r):
# if a[i] >= x:
# break
# for j in reversed(range(p-1, j)):
# if a[j] <= x:
# break
i += 1
j -= 1
while a[i] < x and i < r:
i += 1
pass
while a[j] > x and j > p:
j -= 1
pass
if i >= j:
break
a[i], a[j] = a[j], a[i]
a[p], a[j] = a[j], x
return j
def quicksort(a: list, p: int, r: int):
"""
对列表a[p:r]区间的元素进行排序
:param a: 待排序列表
:param p: 起始位置
:param r: 结束位置(len(a)-1)
:return: 无
"""
if p < r:
# 对a进行划分
q = partition(a, p, r)
# 划分点位置:j
quicksort(a, p, q-1)
quicksort(a, q+1, r)
线性时间选择
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/1/6 21:16
# @Author : Lili
# @File : 线性时间选择.py
# @Description : 求解一般选择问题的分治算法,如果能在线性时间内找到一个划分基准,使醉话情况下
# 按这个基准划分出的子数组长度都至少为原数组长度的ε倍,那么用O(n)时间就可以完成选择任务
import random
from 快速排序 import partition
from 快速排序 import quicksort
def randomized_partition(a: list, p: int, r: int) -> int:
"""
通过随机交换a[p]的值为a[p:r]中某个, 来使中间值的取值随机化,
并调用partition函数来对a进行划分
使得a[p:q-1] <= a[q] <= a[q+1:r]
:param a: 待求取列表
:param p: 起始位置
:param r: 终止位置
:return : 划分中间值的位置 q
"""
i = random.randint(p, r-1)
a[i], a[p] = a[p], a[i]
return partition(a, p, r-1)
def randomized_select(a: list, p: int, r: int, k: int):
"""
找列表a[p:r]中第k(从1开始计数)小的元素, 会改变a中值的顺序
:param a: 待选择列表
:param p: 起始位置
:param r: 终止位置(len(a)-1)
:param k: 选择位置
:return: 元素值
"""
if p == r:
return a[p]
i = randomized_partition(a, p, r)
j = i - p + 1
if k <= j:
return randomized_select(a, p, i, k)
else:
return randomized_select(a, i+1, r, k-j)
if __name__ == "main":
a = [95, 32, 65, 55, 62, 88, 180, 70, 0, 6, 10, 118, 30, 33, 50, 58, 80, 90, 100, 150]
b = a[:]
print(randomized_select(a, 0, len(a), 5))
quicksort(b, 0, len(b)-1)
print(a)
print(b)
采用分治的方法
《计算机算法设计与分析》