Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 按升序或降序排序(任意选择;以较便宜的为准)_Algorithm_Sorting - Fatal编程技术网

Algorithm 按升序或降序排序(任意选择;以较便宜的为准)

Algorithm 按升序或降序排序(任意选择;以较便宜的为准),algorithm,sorting,Algorithm,Sorting,我有一个元素数组。此阵列可以是: 随机洗牌(大约20%的时间) 几乎按升序排序*(大约40%的时间) 几乎按降序排序(大约40%的时间) 但我(事先)不知道这些案例中哪一个适用。我更愿意将数组排序为它已经接近的顺序 输出是升序还是降序并不重要,但它必须是一个或另一个(因此我可以对其执行二进制搜索) 这类产品不一定要稳定 一些背景信息:过程大致如下: 填充数组 按某个属性排序 做一些处理(计算分位数和其他一些次要的东西) 按其他属性B排序 做更多的处理 按属性C排序 做更多的处理 A和B

我有一个元素数组。此阵列可以是:

  • 随机洗牌(大约20%的时间)
  • 几乎按升序排序*(大约40%的时间)
  • 几乎按降序排序(大约40%的时间)
但我(事先)不知道这些案例中哪一个适用。我更愿意将数组排序为它已经接近的顺序

输出是升序还是降序并不重要,但它必须是一个或另一个(因此我可以对其执行二进制搜索)

这类产品不一定要稳定


一些背景信息:过程大致如下:

  • 填充数组
  • 按某个属性排序
  • 做一些处理(计算分位数和其他一些次要的东西)
  • 按其他属性B排序
  • 做更多的处理
  • 按属性C排序
  • 做更多的处理
A和B通常相互关联(但可能是正的或负的)。这同样适用于B和C。偶尔A==C

*这里的“接近排序”意味着大多数元素都接近它们的最终位置。但很少精确到它们的最终位置(存在大量的加性噪声,并且没有太多长的排序子序列)。尽管如此,通常在数组的开始和结束处有一些“异常值”,它们对下一个排序的顺序预测能力很差



是否有一种算法可以利用我不喜欢升序或降序的事实,以更便宜的方式进行排序(与我目前使用的TimSort相比?

我会继续使用TimSort(但是,一个好的替代方法是*),但首先探测数组以决定是按升序还是降序排序。查看第一个和最后一个元素,并相应地进行排序。如果数组未排序,则选择无关紧要;如果它是(部分)排序的,则以较宽的间隔进行探测更有可能正确检测哪种方式


*Smoothsort与Timsort具有相同的最佳、平均和最坏情况时间,并且具有更好的空间复杂度。与Timsort一样,它是专门为利用部分排序的数据而设计的。

考虑的另一种可能性:

  • 开始执行(手动滚动)插入排序
  • 当你走的时候,数一数你做的倒转的次数
  • 在完成少量固定数量的插入后,将已计算的反转数与该点发生的最大反转数进行比较,前提是首先对数据进行反向排序:
  • 如果比例接近0,则(可能)数据几乎已排序。完成插入排序,它在几乎排序的数据上执行得非常好。如果你不喜欢“可能”的声音,那么继续计算倒数,如果倒数低于某个阈值,准备返回Timsort
  • 如果比例接近1,那么(可能)数据几乎是反向排序的,并且在开始时有少量已排序的元素。将它们移到末尾,反转它们,并使用反转比较器完成插入排序
  • 否则数据是随机的,请使用您喜欢的排序算法。我想说的是Timsort,但由于它在几乎排序的数据上做得很好,所以肯定有其他算法比Timsort在均匀无序数据上做得至少好一点点。可能是没有Tim的简单合并排序
“小固定数”可以是插入排序相当快的数字,即使在不好的情况下也是如此。我猜大概是10-20左右。对于任意给定的插入次数和任意给定的“接近0/1”阈值,都可以计算出均匀混合数据中的假阳性概率,但我太懒了

您说第一个和最后几个数组元素通常与趋势相反,在这种情况下,您可以将它们从初始测试插入排序中排除


显然,这种方法在某种程度上受到了Timsort的启发。但是Timsort对包含运行的数据进行了恶魔般的优化——我尝试过只对接近一次大运行的数据进行恶魔般的优化(在任何方向)。Timsort的另一个特点是,它经过了很好的测试,我不想与大家分享。

+1(尽管“几乎排序”可能意味着什么,所以可能需要探测两个以上的边界元素)对您的原理感到好奇,即探测更宽的间隔更有可能探测到排序方向…@Groo-确实如此。也许比较第一个k元素和最后一个k元素。然而,在某种程度上,决定订单的成本开始成为一个重要因素;请注意,如果您使用自己的Timsort,您可以在收集minruns时决定降序/升序。@Triptych-这只是基于OP对数据可能受到干扰的描述的一种启发式方法。这个顺序与前面的排序“相关”,这对我来说意味着更大的间距更有可能检测到趋势(如果有)。有什么原因你不能预先计算索引吗?@Triptych:它们会很短。通常,在丢弃数组之前,每个排序属性只使用一次(仅保留“执行处理”步骤的结果)