当前位置: 首页 > 知识库问答 >
问题:

为什么快速排序的JDK实现有堆栈溢出的风险?

羊舌高爽
2023-03-14

前几天我看了一个演讲,演讲者使用了McIlroy的论文《快速排序的致命对手》中概述的技术来生成数组的输入。为将触发O(n2行为的基元类型排序。该序列导致pivot选择总是将数组大小减少一个常数,这导致了Java数组。sort函数导致堆栈溢出。

根据JDK的源文件,Arrays.sort1快速排序实现函数没有防止堆栈溢出的保护措施。通过让排序例程不触发两次递归调用,而是使用时循环为较大的子数组重用当前堆栈帧,并且只递归一次(在较小的子数组上),始终可以使快速排序永远不会堆栈溢出。这会导致最小的性能下降,并且使得任何合理大小的输入都不可能导致堆栈溢出,因为在大小为n的输入上堆栈深度永远不会超过O(log n)堆栈帧。为了防止这种情况发生,作者还可以使用内隐排序算法,当快速排序递归深度超过某个限制时,它修改快速排序以切换到最坏情况下的O(n log n)排序算法。

有什么理由让数组的作者。排序没有选择这样做?内置排序算法可能导致堆栈溢出,这似乎是一个严重的问题,因为它可能通过触发重复的堆栈溢出来对此类系统发起DoS攻击。

共有1个答案

宗穆冉
2023-03-14

为什么?因为解决这个问题太过分了。

所使用的算法在除了异常情况之外的所有情况下都是稳定的,如果这些情况比通常情况下更有可能发生,那么这种情况将在外部得到防范。这就是为什么他们有API留档来定义幕后使用的算法。所以你可以防御它。

破坏所提出算法的特定顺序的可能性非常小。

我希望如果您仔细观察,就会发现一些数据集会导致几乎所有标准JVM结构崩溃。保护它们的成本是多少?这一成本值得付出努力吗?由于防御措施,算法不可避免地会退化。

 类似资料:
  • 我有一个执行快速排序的应用程序。在我开始给它一些更大的数字(我第一次得到它是10000000)之前,它工作得很好。我知道是由递归引起的,但我不明白为什么我的应用程序会因此而崩溃。如有任何建议,将不胜感激。这是我的密码:

  • 问题内容: 我目前正在用Java编写一种快速排序算法,以对整数的随机数组进行排序,然后使用System.nanoTime()对它们进行计时。这些数组的大小是10的幂,从10 ^ 3到10 ^ 7结束。此外,随机列表具有不同的属性。我正在对纯随机列表进行排序,具有一些相同值的列表(fewUnique),反向排序的列表,已排序的列表和几乎已排序的列表。 排序有效。它对数组进行递归快速排序,直到需要对数

  • 尝试使用Hoare分区方案实现快速排序,但我遇到了一个问题,即无论数组大小如何,更改pivot的索引都会导致溢出。代码: 这个实现选择低索引(这里名为min)作为轴心元素,这样做很好。但是,将pivot元素更改为任何其他索引都会导致StackOverflow错误,而与正在排序的数组的大小无关。(错误参考第3行,其中调用了partition())我最好在(min,max)范围内随机选择pivot元素

  • 问题内容: 我的第一段代码是我的项目对象文件;第二个是主班。在运行代码没有任何问题之前,但是在添加读写文件之后,我的代码开始收到堆栈流错误。只是正在调用错误的代码段。 我的主班: 如何找到导致堆栈溢出的地方? 问题答案: 创建: 并创造 因此,在初始化时,您将不断创建这些对象 有一个类似的Baeldung示例,用于获取StackOverflowError 由于ClassOne的构造函数实例化了Cl

  • 问题内容: 我在此演示文稿中阅读了http://golang.org/doc/ExpressivenessOfGo.pdf 第42页: 安全 -没有堆栈溢出 这怎么可能?和/或Go如何避免这种情况? 问题答案: 这是一个称为“分段堆栈”的功能:每个goroutine都有自己的堆栈,并在堆上分配。 在最简单的情况下,编程语言实现在每个进程/地址空间使用单个堆栈,通常通过称为和(或类似名称)的特殊处理