python - 经验性测量 QuickSelect 的时间复杂度
问题描述
我知道时间复杂度应该是O(N)
. 但是,当我根据经验对其进行测试时,会得到奇怪的结果。有人可以解释发生了什么吗?
def insertPivot(array, start, end):
pivot = end
i = start
j = end - 1
while i < j:
while array[i] < array[pivot] and i < j:
i += 1
while array[j] > array[pivot] and j > i:
j -= 1
array[i], array[j] = array[j], array[i]
if array[i] > array[pivot]:
array[i], array[pivot] = array[pivot], array[i]
pivot = i
return pivot
def quickselect(array, k):
start = 0
end = len(array) - 1
pivot = insertPivot(array, start, end)
while pivot != k - 1:
if pivot < k - 1:
start, end = pivot, end
else:
start, end = start, pivot - 1
pivot = insertPivot(array, start, end)
return array[k - 1]
这就是我如何得到我的测量结果
import random
import timeit
import numpy as np
av_times = dict()
for n in [10, 100, 500, 1000, 5000, 10000]:
times = list()
array = list(range(n))
for _ in range(10):
random.shuffle(array)
k = random.randint(0, n)
times.append(
timeit.timeit(lambda: quickselect(array, k), number=10)
)
av_times[n] = sum(times) / len(times)
xx, yy = zip(*av_times.items())
xx, yy = np.log(xx), np.log(yy)
m, b = np.polyfit(xx, yy, 1)
斜率系数m
为1.5
,表明时间复杂度为O(N*sqrt(N))
解决方案
insertPivot
确实具有O(N)复杂性,因为您增加i
和减少j
直到j
不再大于i
. 但是,insertPivot
是嵌入到while循环里面的quickselect
。因此,无论 的复杂度如何quickselect
,都会乘以 的复杂度insertPivot
,因为在循环的每一步都会执行O(n)复杂度的算法。如果pivot < k - 1
,则增加区间的左边界。否则你减少到pivot - 1
. 因此,在循环中,您通过其左边缘和枢轴之间的差异来减少每一步的间隔大小。根据您可以使用什么函数来估算步数,您可以确定将线性复杂度中的 N 与什么相乘,从而得出实际复杂度。
推荐阅读
- python - pymysql.err.OperationalError: (1241, '操作数应包含 1 列')。我无法确定错误
- fonts - 如何在 OpenType GPOS 查找格式 4.1 中查找基本字符?
- swift - 无法使用 HKWorkoutSession 开始锻炼课程
- python - 如何从两个字典中计算一个特殊的指标?
- android - Android Compose - 如何平铺/重复位图/矢量?
- python - 即使我调整主窗口的大小,QWidget.rect 的大小也不会改变
- php - 如何在 localhost/xampp 服务器上发送电子邮件?
- node.js - 如何在 opensubtitle API 中使用语言过滤搜索
- python - 仅在将 RandomForest max_features 参数添加到 RandomizedSearchCV
- swiftui - 将滑块值保存到数组 SwiftUI