比较元素时我可以使用哪些排序技术?

fuz*_*fuz 25 sorting algorithm comparison performance

问题

我在我想要进行排序阵列的应用一个元件的一个0,一个1,...,A N-1 .我有一个比较功能CMP(I,J) ,其比较元件一个一个Ĵ和交换功能的交换(I,J) ,该交换元件一个一个Ĵ阵列的.在应用程序中,cmp(i,j)函数的执行可能非常昂贵,以至于cmp(i,j)的一次执行比排序中的任何其他步骤花费的时间更长(除了其他cmp(i,j) )当然要求).你可能会认为cmp(i,j)是一个相当冗长的IO操作.

请假设为了这个问题,没有办法让cmp(i,j)更快.假设所有可能使cmp(i,j)更快的优化已经完成.

问题

  • 是否有一种排序算法可以最小化对cmp(i,j)的调用次数?

  • 在我的应用程序中可以编写一个昂贵的谓词(i,j),如果调用cmp(i,j)需要很长时间,则该谓词是真的.昂贵的(i,j)便宜且昂贵(i,j)∧昂贵(j,k)→昂贵的(i,k)大部分都在我目前的应用中.但这并不能保证.

    昂贵(i,j)的存在是否允许更好的算法试图避免昂贵的比较操作?如果是的话,你能指点我这样的算法吗?

  • 我想指出有关这个主题的更多材料.

这是一个与我的应用程序完全不同的示例.

考虑一组可能很大的文件.在此应用程序中,目标是在其中查找重复文件.这基本上归结为通过一些任意的标准对文件进行排序,然后按顺序遍历它们,输出遇到的相同文件的序列.

当然,大量数据中的读取器是昂贵的,因此,例如,可以仅读取每个文件的第一兆字节并计算该数据的散列函数.如果文件比较相等,则散列也是如此,但反过来可能不成立.两个大文件只能在接近结尾的一个字节中有所不同.

在这种情况下,昂贵的(i,j)的实现只是检查哈希值是否相等.如果是,则需要进行昂贵的深度比较.

pat*_*cek 9

我会尽力回答每个问题.

  • 是否有一种排序算法可以最小化对cmp(i,j)的调用次数?

传统的排序方法可能有一些变化,但一般来说,对列表排序所需的最小比较数量存在数学限制,并且大多数算法都利用了这一点,因为比较通常并不便宜.您可以尝试按其他方式进行排序,或尝试使用可能更接近真实解决方案的快捷方式.

  • 昂贵(i,j)的存在是否允许更好的算法试图避免昂贵的比较操作?如果是的话,你能指点我这样的算法吗?

我不认为你可以解决至少进行最小数量比较的必要性,但你可以改变你比较的东西.如果您可以比较数据的哈希值或子集而不是整个事物,那肯定会有所帮助.您可以采取的任何简化比较操作的方法都会产生很大的不同,但如果不了解数据的具体细节,就很难提出具体的解决方案.

  • 我想指出有关这个主题的更多材料.

看看这些:


tem*_*def 7

平均排序n个元素数组所需的理论最小比较次数是lg(n!),约为n lg n -n.如果您使用比较来对元素进行排序,那么平均没有办法比这更好.

在标准的O(n log n)基于比较的排序算法中,mergesort进行最低比较次数(仅约n lg n,而快速排序约为1.44 n lg n,而对于heapsort约为n lg n + 2n),因此它可能是一个很好的算法用作起点.通常,mergesort比heapsort和quicksort慢,但这通常假设比较快.

如果你确实使用mergesort,我建议使用像自然mergesort这样的mergesort的自适应变体,这样如果数据大部分被排序,那么比较的数量就更接近线性.

还有其他一些选择.如果您知道数据已经大部分已排序,您可以使用插入排序或标准版本的heapsort来尝试加快排序.或者,您可以使用mergesort,但在n很小时使用最佳排序网络作为基本情况.这可能会减少足够的比较,从而为您带来显着的性能提升.

希望这可以帮助!

  • @ SaeedAmiri-排序下限的标准证明仅讨论最坏情况的运行时,但是可以通过查看从根到任何路径的所有路径的平均长度来修改它以讨论平均情况运行时.叶节点.您可以使用树具有高度log(n!)的事实来表明平均路径长度也必须至少为log(n!).此链接提供了一个证据,例如:http://www.cs.cmu.edu/~avrim/451f11/lectures/lect0913.pdf.希望这可以帮助! (2认同)

Giu*_*nco 0

快速排序和合并排序是最快的排序算法,除非您有有关要排序的元素的一些附加信息。他们需要 O(n log(n)) 次比较,其中 n 是数组的大小。数学证明任何通用排序算法都不可能比它更有效。

如果您想让过程更快,您可以考虑添加一些元数据来加速计算(除非您也是如此,否则不能更精确)。

如果您知道更强的东西,例如最大值和最小值的存在,则可以使用更快的排序算法,例如基数排序或桶排序。

您可以在维基百科上查找所有提到的算法。

据我所知,你无法从昂贵的关系中受益。即使你知道这一点,你仍然需要进行这样的比较。正如我所说,您最好尝试缓存一些结果。


编辑

我花了一些时间考虑这个问题,并提出了一个稍微定制的解决方案,我认为该解决方案将进行尽可能少的昂贵比较,但完全忽略比较的总数。它最多会进行 (nm)*log(k) 昂贵的比较,其中

  • n 是输入向量的大小
  • m是易于相互比较的不同成分的数量
  • k 是难以比较且具有连续等级的元素的最大数量。

是算法的描述。毫无疑问,它的性能会比简单的合并排序差很多,除非 m 大而 k 小。总运行时间为 O[n^4 + E(nm)log(k)],其中 E 是昂贵比较的成本(我假设 E >> n,以防止它从渐近符号中消失。 n^4 可能可以进一步减少,至少在平均情况下是这样。

编辑

我发布的文件包含一些错误。在尝试的过程中,我还修复了它们(我忽略了 insert_sorted 函数的伪代码,但这个想法是正确的。我编写了一个 Java 程序,对整数向量进行排序,并按照您的描述添加了延迟。即使我对此表示怀疑,但它实际上如果延迟很大,则比归并排序更好(我在整数比较中使用了 1 秒延迟,这通常需要纳秒来执行)

  • “快速排序是最快的......”这个论点不太适用。首先,快速排序有一些病理情况,执行时间为 *O(n²)*,所以它可能不是最好的,其次,如果算法花费的成本更便宜,我不会关心算法是否花费 *O(n³)* 时间与快速排序相比。这就是问题的重点。 (3认同)
  • @Giulio 说 C 可能太大了,对于实际问题来说并不重要。这里的情况正是如此。 (2认同)