BQN:实施订购函数

2021-06-17 04:23:09

订购功能是排序(∧∨),等级(⍋⍒)和垃圾箱(⍋⍒)。虽然这些都是很好的研究 - 特别是分类,然后是二进制搜索或"前身搜索" - 最近的发展,以及我在文学中找不到的技术。这三个功能密切相关,但在哪些算法中具有重要差异。排序是一种非常深刻的深层问题,不同的算法能够做出广泛的惊人的东西,以及组合那些的精致方式。它绝不是解决的。相比之下,箱子很驯服。

在订购复合数据和简单数据之间存在大划分。对于复合数据比较是昂贵的,并且最好的算法通常是使用最少比较的算法。对于简单的数据,他们在便宜且非常便宜之间的某个地方,并且花哨的无分支和矢量化算法是最好的。

合并排序更好。它是确定性的,稳定的,并且具有最佳的最坏情况性能。它的模式处理更好:合并分类处理"横向"模式和Quicksort与#34;垂直" Merge Sort会在任何运行顺序中获取有用的工作,但就是Quicksort将快速敲打其模拟,直到它也可以随机。

但这并不是卑鄙的合并排序总是更快。 Quicksort似乎有点不合时宜。用于排序,Quicksort' s分区可以减少足以使用极其快速的计数排序的数据范围。分区也是一种自然适合二进制搜索,其中' s强制性,具有足够大的参数的明智的缓存行为。所以它可以很有用。但它并不合并,并且可以易于融合,并且'令人羞耻。

这同样适用于分区的一般类别(QuickSort,Radix Sort,Samplesort)和合并排序(合并,Timsort,Multimerges)。除了某些类型和长度的虽然分散的访问使其性能不可预测,但是,基拉排序肯定是最佳的,但我认为他们整体思考它们'重申不值得。一百万均匀随机的4字节整数几乎是最佳的基数的案例,因此这似乎是进入分拣基准的事实意味着基数排序看起来比它更好。

二元搜索很容易出错。不要写(嗨+ lo)/ 2:它'不受溢出的安全。我始终遵循在此处的第一个代码块中给出的模式。此代码将永远不会访问值*基础,因此应该被视为在基本+ 1开始的n - 1值上的搜索(完美的情况是当值的数量小于两个时,这是事实是如何要去的)。它' scrantless,始终采用相同数量的迭代。要获取已知答案时停止的版本,请在* MID<的情况下从n中减去n%2。 X。

阵列比较价格昂贵。这里的目标几乎完全是为了最大限度地减少比较次数。哪个复杂的目标远远不如充分利用现代硬件,因此这里的算法更简单。

用于排序和等级,使用Timsort。它'时间测试并没有显示弱点迹象(但是确实可以在正式验证中拿到2015年发现的错误的修复)。几乎没有与随机数据上的最佳比较编号不同,以及出色的模式处理。等级可以通过从原始阵列中选择来订购指数或通过与指数相同的顺序移动数据。我认为这一部分最终对小型元素来说基本上更好。

对于箱,使用分支二进制搜索:请参阅上面的二进制搜索。但也有趣(虽然,我期待,罕见)案件,只有一个论据是化合物。应该减少此参数的元素以适合其他参数的类型,然后与多个元素进行比较。对于正确的参数,这只是意味着在做任何二进制搜索都适合左参数之前减少。如果左参数是化合物,则其元素应用作分区。然后仅在分区获得非常小的时间 - 可能是一个元素时才会切换回二进制搜索。

感兴趣的排序算法正在计算排序和PDQSORT(稍后在此描述我自己的一些改进)。然而,这些既不可用的等级。

对于小范围等级,必须以显着的性能成本用桶排序替换计数排序。我没有任何方法i' m满意的其他数据。通过在末端排序索引来稳定PDQSORT,但慢速。 Wolfsort是一种混合基数/合并的排序,可能更好。

ips⁴o是一个可怕的复杂的样式。稳定,我想。对于非常大的阵列,它可能具有最佳的内存访问模式,因此一些Samplesort通过可能是有用的。

计数和桶排序都是通过计算每个可能值的数量而开始的小型算法。这里使用的铲斗排序意味着当时使用计数来放置在另一个通过的结果中的适当位置。计数排序不再从初始值读取,而是从计数重建它们。它可以在BQN中写入(/≠¨∘⊔)⌾( - ⟜min),具有≠≠¨∘作为单一的高效操作。

铲斗排序可用于等级或排序(⍋⊸⊏),但计算SORT​​仅用于对本身进行排序。它' s not-op-of-unsstable:'在结果值和输入​​值之间没有连接,但它们构造为相等。但是通过快速指数,计数排序是非常强大的,并且有效的范围是参数长度的四到八倍。这足够大,它可能会造成内存使用问题,但可以通过分区任意低廉的内存使用。