使用三个数字比较器进行排序
Sorting using a three number comparator
>我有一个大小为 n 的数组等待排序。但与普通的排序问题不同,我不得不使用特定的比较器,它接收三个数字并告诉三个数字的最大值和最小值。我的目标是在对数组进行完全排序之前尽可能少地使用比较器。我可以使用什么策略?
感谢您的任何帮助!
由于您的三路比较器可以通过对普通比较器的三次调用来实现,这意味着我们不能将任何正态排序算法改进超过 3 倍。一个更仔细的论证表明,因为每个三向比较都给了我们 log₂ 6 ≈ 2.585 位的信息,我们不能改进超过这个数字。直观地说,当使用普通比较器排序时,您可能会比较a <= b
和b <= c
,因此无论如何都不需要比较a
和c
;因此,可能的加速系数可能小至 2。
因此,渐近地,我们仍在寻找O(n logn(算法,问题是如何利用比较器进行至少2倍的比较。首先要尝试的"明显"事情是修改现有的基于比较的排序算法;一个很好的候选者是自下而上的堆排序,它在平均情况下进行大约 n 个 log₂ n 比较,在最坏的情况下进行 1.5 n 个 log₂n的比较(维基百科(。这击败了标准的快速排序算法,该算法在平均情况下进行大约 1.39 n log₂n比较(维基百科(。
该算法在堆上使用两个基本操作,"筛选"和"筛选"。
- "筛选"操作需要将父元素与其两个子元素进行比较,以查看父元素是否大于或等于其两个子元素,或者如果不是,则应与哪个子元素交换父元素。我们可以使用三路比较器同时比较父母和两个孩子。
- "筛选"操作将子节点与其父节点进行比较,如果子节点顺序不正常,则交换它们;然后一直重复此操作,直到根节点。我们可以使用三向比较器将子节点与其父节点和祖节点同时进行比较。
堆排序算法仅在这两个操作中调用比较器,对于这两个操作,三向比较器的调用次数可以减少 2 倍。这不一定是你能做的最好的事情,但它从一个非常有效的算法开始,并与直觉给出的最坏情况加速系数相匹配。
嗯,我想出了一个主意。
让我们记住快速排序的工作原理:
- 首先,我们找到一种中值(如果你太懒了,
(a[0] + a[N-1])/2
拿起=3(。 - 然后,我们划分一个数组 在小于或大于中位数的条件下由 2 。
- 最后,我们在两个子数组中的每一个递归运行算法
使用比较器,您可以通过一次处理两个值来加快第二阶段的两倍:
compare(median, a[2 * i], a[2 * i + 1])
- 如果 min 是中位数,则两者都更大并转到正确的子数组
- 如果 max 是中位数,则两者都较小并转到左侧子数组
- 如果两者都不是中位数,则最小值向左,Max 向右
之后,像往常一样运行算法的递归部分。
好吧,我有一个绝妙的主意。根据我的粗略估计,使用 4 路合并排序和失败者树进行优化,使用比较器的次数可以减少到 0.5nlog₂n 以下。
- std::设置自定义比较器
- C++中"std::sort"比较器的不同类型
- 将 std::set 与基于键的比较器一起使用
- 带自定义比较器的最小优先级队列
- 函数类作为比较器
- 优先级队列自定义比较器
- 什么是自定义比较器以及如何在 C++ 的排序函数中使用它?
- 没有默认构造函数作为模板参数的自定义比较器
- set_intersection使用自定义设置比较器
- 如何为集合 c++ 建立比较器
- C++复杂情况的比较器通过参数问题
- 对于BTreeMap和其他依赖于Ord的东西,是否有等效于C++比较器对象?
- 对没有比较器或λ函数的向量进行排序?
- "operator()"在重载运算符方法中是什么意思,在priority_queue(STL)中用作C++中的比较器?
- 用户定义的结构是否有默认C++比较器?
- C++设置了一个用于排序的比较器和另一个用于唯一性的比较器
- 使用迭代器的自定义比较器函数
- 使用三个数字比较器进行排序
- sort() 方法 c++ 中的比较器函数.为大量数字获得不同的解决方案
- C++ 标准::设置<string>字母数字自定义比较器