我一直不明白,第 k 大的数的正解为什么时间复杂度是 O(n)。看快排代码,二分递归代码一眼就是 O(nlog n),一看题解,全都说证明在算法导论,自己看书。 我看不懂书,因此想尝试做一个 benchmark,通过数据规模增长和 benchmark 用时来判断其时间复杂度。
- 生成足够数量的随机数。后续所有测试都在这样同一个相对随机的数据上进行。
- find_kth_largest 函数为 leetcode 题解(基于快速排序的选择方法) 改写为 rust 版本的结果。
注:find_kth_largest 函数本身没有 clone;我在 benchmark 之前就进行了数据 clone。
测试结果为(已排序,否则 cargo test 输出的排序为 10 100 1000 10000 50 500 5000):
test tests::bench_find_kth_largest_10 ... bench: 17.07 ns/iter (+/- 2.93)
test tests::bench_find_kth_largest_50 ... bench: 374.54 ns/iter (+/- 96.44)
test tests::bench_find_kth_largest_100 ... bench: 1,800.08 ns/iter (+/- 251.31)
test tests::bench_find_kth_largest_500 ... bench: 32,918.46 ns/iter (+/- 2,464.11)
test tests::bench_find_kth_largest_1000 ... bench: 125,544.36 ns/iter (+/- 14,766.95)
test tests::bench_find_kth_largest_5000 ... bench: 2,960,778.11 ns/iter (+/- 203,536.92)
test tests::bench_find_kth_largest_10000 ... bench: 11,616,331.11 ns/iter (+/- 382,382.89)
然后我对其进行画图。对数据规模(横轴)和用时(纵轴)同时取对数,再拟合:
from math import log
import matplotlib.pyplot as plt
a = [
[10, 17.07],
[100, 1800.08],
[1000, 125544.36],
[10000, 11616331.11],
[50, 374.54],
[500, 32918.46],
[5000, 2960778.11],
]
a.sort(key=lambda x: x[0])
x = [log(i[0]) for i in a]
y = [log(i[1]) for i in a]
plt.plot(x, y)
plt.show()结果为:
可以看出这是一条斜率大约为 1.9 的直线,也就是说

