Algorithm 快速排序中的随机洗牌如何帮助提高代码的效率?

Algorithm 快速排序中的随机洗牌如何帮助提高代码的效率?,algorithm,sorting,shuffle,Algorithm,Sorting,Shuffle,我在看罗伯特·塞奇威克(Robert Sedgwick)关于算法的讲座视频,他解释说,随机洗牌确保我们不会在快速排序中遇到最坏的二次时间情况。但我无法理解是如何发生的。假设最坏的情况——所有事情都已经排序好了——足够频繁,值得担心,而洗牌是一种黑魔法,它是一种最省力的草率方式,可以避免这种情况,而不必承认通过改进这种情况,你正在将问题转移到另一个问题,它碰巧被随机地按顺序排列。希望这种糟糕的情况更为罕见,即使出现这种情况,随机性也意味着问题不容易重现,也不能归咎于这种欺骗 以牺牲罕见案例为代价改

我在看罗伯特·塞奇威克(Robert Sedgwick)关于算法的讲座视频,他解释说,随机洗牌确保我们不会在快速排序中遇到最坏的二次时间情况。但我无法理解是如何发生的。

假设最坏的情况——所有事情都已经排序好了——足够频繁,值得担心,而洗牌是一种黑魔法,它是一种最省力的草率方式,可以避免这种情况,而不必承认通过改进这种情况,你正在将问题转移到另一个问题,它碰巧被随机地按顺序排列。希望这种糟糕的情况更为罕见,即使出现这种情况,随机性也意味着问题不容易重现,也不能归咎于这种欺骗


以牺牲罕见案例为代价改进常见案例的理念是好的。将随机性作为实际考虑哪些情况更常见或更不常见的一种替代方法有些草率。

随机洗牌对输入空间上的分布有什么影响?为了理解这一点,让我们看看概率分布,
P
,它定义在一组
s
上,其中
P
不在我们的控制范围内。让我们通过在
S
上对
P
应用随机洗牌来创建概率分布
P'
。换句话说,每次我们从
P
获取样本时,我们都会将其均匀随机地映射到
S
的一个元素。对于这个结果分布
P'
,您能说些什么

P'(x) = summation over all elements s in S of P(s)*1/|S| = 1/|S|
因此,
p'
只是
S
上的均匀分布。随机洗牌使我们能够控制输入概率分布


这与快速排序有什么关系?我们知道快速排序的平均复杂性。这是由均匀概率分布计算出来的,这是我们想要在输入分布上保持的属性,不管它实际上是什么。为了实现这一点,我们对输入数组进行随机洗牌,以确保分布在任何方面都不是对抗性的。

事实上,我们承认,尽管我们经常谈论平均案例复杂性,但实际上并不期望每个案例都以相同的概率出现

在快速排序中,对已排序的数组进行排序是最糟糕的情况,因为每当您选择一个轴时,您会发现所有元素都放置在轴的同一侧,因此根本不会分成大致相等的两部分。通常在实践中,这种已经分类的案例会比其他案例更频繁地出现

首先随机洗牌数据是一种快速的方法,可以确保所有情况都以相同的概率出现,因此这种最坏的情况与任何其他情况一样罕见

值得注意的是,还有其他一些策略可以很好地处理已排序的数据,例如选择中间元素作为轴心。

视频在吗? 不幸的是,使用数据N,N,…,N,1,1,…,1将性能降低到O(N^2)。 我已经用它检查过了,生成了这样的数据

$ for N in 10000 20000 30000 40000; do time ./nn11.awk $N | java Quick; done | awk 'NF>1'

real    0m10.732s
user    0m10.295s
sys     0m0.948s

real    0m48.057s
user    0m44.968s
sys     0m3.193s

real    1m52.109s
user    1m48.158s
sys     0m3.634s

real    3m38.336s
user    3m31.475s
sys     0m6.253s

在随机快速排序的情况下,由于轴心元素是随机选择的,因此我们可以预期输入数组的分割平均而言是相当均衡的,而不是在算法的非随机版本中进行1和(n-1)分割。这有助于防止在不平衡分区中发生快速排序的最坏情况


因此,快速排序随机版本的平均案例运行时间为O(nlogn),而不是O(n^2)

Robert Sedgewick的讲座非常有用,很容易理解,以后在实践中使用。我同意他们很容易理解,我所说的是我无法理解这一部分。大量的O(n)洗牌并不重要。n、 n,…,n,1,1,…,1被混洗成可能的锯齿形图案。即使数据n,1,n,1,…,n,1,n没有被洗牌,Quick.java的时间复杂度也是O(n^2)。如果数组的所有元素都相同,会有帮助吗?