【问题标题】:How to perform stable sort in C++ when using a custom comparator?使用自定义比较器时如何在 C++ 中执行稳定排序?
【发布时间】:2021-05-31 00:07:55
【问题描述】:

我正在尝试用 C++ 编写一个自定义比较器来对向量进行排序。为了简单起见,我会说我的排序标准是所有偶数值都应该在所有奇数值之前,我正在尝试为此编写一个自定义比较器。但我需要确保保留所有偶数元素和所有奇数元素的相对顺序。

我正在使用此代码:

bool mysort(int arg1,int arg2){
    return arg1%2==0;
}

int main(){
    vector<int> v({1,3,2,4,5,7,9,6,8,11,10,12});
    stable_sort(v.begin(),v.end(),mysort);
    for(int i=0;i<v.size();i++){
        cout<<v[i]<<" ";
    }
    return 0;
}

根据我的理解,当 mysort() 返回 true 时,这意味着允许第一个参数 (arg1) 在第二个参数 (arg2) 之前。这就是我在比较器中使用return arg1%2==0; 的原因。

但我得到的输出是12 10 8 6 4 2 1 3 5 7 9 11。这意味着,偶数元素的相对顺序是相反的。同时,奇数元素的相对顺序被保留。

相反,如果我在mysort() 比较器中使用return i%2==0 &amp;&amp; j%2!=0;,我得到的输出是2 4 6 8 10 12 1 3 5 7 9 11。它保留了所有奇数和偶数元素的相对顺序。

为什么会出现这种行为?编写自定义比较器并保留相似元素的相对顺序的最佳方法是什么?提前谢谢你。

【问题讨论】:

  • @NateEldredge 它甚至没有这样做,因为它忽略了一个参数。 (不确定是哪一个,因为它们都同名!)正如所写的那样,2 在 4 之前 并且 4 在 2 之前。
  • 虽然这不是您问的问题,但如果您真的想根据每个元素的某些属性稳定地重新排序容器,请查看stable_partition。鉴于您的示例,它可能比完整排序算法更适合。
  • @RaymondChen 抱歉,这是参数名称的错字。现在已修复。参数是 arg1 和 arg2
  • @DaveS 我不是在寻找像 stable_partition 这样的东西。但现在看起来它对我正在做的事情很有用。谢谢

标签: c++ sorting c++14 comparator stable-sort


【解决方案1】:

我相信您知道,stable_sort 保留了比较相等的元素的顺序。为此,mysort (i, j)mysort (j, i) 必须在 ij 比较相等时返回 false。 (当然,i &lt; j 时也必须返回 true。)

因此,您必须在mysort 中同时测试arg1 % 2arg2 % 2 才能履行此合同,而return arg1 % 2 == 0 &amp;&amp; arg2 % 2 != 0; 正是您想要的:当arg1 % 2 和@ 都返回时,它将返回false 987654335@无论参数传递的顺序如何,都比较相等。

【讨论】:

  • 谢谢。所以我有一个关于自定义比较器如何工作的问题。当mysort(i,j) 返回真时,sort() 决定i&lt;j,但当mysort(i,j) 返回假时,它检查mysort(j,i)。如果这也返回 false,则 sort() 决定 i==j 但如果 mysort(j,i) 返回 true sort() 决定 i&gt;j。是这样的吗?
  • @JayModi 不完全是。当mysort(i,j) 返回true 时,mysort(j,i) 一定不能返回true。如果是这样,那么mysort 违反了sort/stable_sort 的前提条件。结果是垃圾,也就是未定义的行为。
【解决方案2】:

sortstable_sort 的比较器必须引入严格的弱顺序。您的比较器不满足此条件。

严格弱顺序的属性之一是,对于ij 的任何允许值,mysort(i,j)mysort(j,i) 最多可以返回true .对于这两种情况,例如 i=2j=4,您的比较器都会返回 true

要解决此问题,您必须修改比较器。 arg1 什么时候“小于”arg2?只有一种情况:arg1 是偶数,arg2 是奇数。因此,一个可用的定义是:

bool mysort(int arg1,int arg2){
    return arg1 % 2 == 0 && arg2 % 2 != 0;
}

顺便说一句,当您定义一个比较器时,您根本没有时间考虑算法将按什么顺序传递参数。所有(早期,后来)的讨论都是无关紧要的。该算法将按照它喜欢的顺序传递参数。没有任何保证。

【讨论】:

    【解决方案3】:

    STL 使用小于比较,这意味着 std::stable_sort() 会以相反的顺序传递参数,它会调用 mysort(later_object, early object),所以如果 later_object = early_object 则返回 false(将 early_object 复制到合并输出)。

    【讨论】:

    • 我以为是mysort(earlier_object, later_object)。如果sort(不是stable_sort),情况如何?这里我假设earlier_object 表示原始数组中索引较低的对象。
    • @JayModi - 保留相等元素的顺序仅用于稳定排序,因此 mysort() 的参数必须是(稍后,更早)。对于不稳定的 std::sort ,相等元素的顺序无关紧要,参数的顺序可以是(较早,较晚)或(较晚,较早)。在 Visual Studio 的情况下,std::sort() 和 std::stable_sort() 都对
    猜你喜欢
    • 2020-10-22
    • 1970-01-01
    • 1970-01-01
    • 2013-11-04
    • 1970-01-01
    • 2012-07-05
    • 1970-01-01
    • 2020-10-24
    • 2020-02-24
    相关资源
    最近更新 更多