c++ 为什么我的比较器功能不起作用?

2wnc66cl  于 2023-04-01  发布在  其他
关注(0)|答案(2)|浏览(259)

我有一个元素为[0, 1, 0, 3, 12]的数组。我想把所有的零移到它的末尾,同时保持非零元素的相对顺序。移位后的数组应该像这样[1, 3, 12, 0, 0]。所以我写了下面的代码:

#include <bits/stdc++.h>

using namespace std;

bool cmp(int a, int b){
    if (a == 0) {
        return a > b;
    } else {
        return true;
    }
}

int main(){
    int arr[] = {0, 1, 0, 3, 12};
    sort(arr, arr + 5, cmp);
    for (int i: arr) {
        cout << i;
    }
}

我写这段代码的想法是,通过返回false,每当零被放置在一个非零元素之前,i可以交换元素,但这段代码给出的输出为[12, 3, 1, 0, 0],即它只是按降序排序的元素。有人能解释我为什么我的比较器函数不工作吗?我可以使用比较器函数来做到这一点吗?

2eafrhcq

2eafrhcq1#

您的比较函数不满足比较函数的要求。例如,如果cmp( a, b )返回true,则cmp( b, a )应返回false
不使用算法std::sort,而是使用算法std::stable partition,例如

std::stable_partition( std::begin( arr ), std::end( arr ), 
        []( const auto &x ) { return x != 0; } );

另一方面,如果非零元素不按例如

int arr[] = { 0, 3, 0, 12, 1 };

如果你想对它们进行排序,你可以用下面的方式来调用std::sort

std::sort( std::begin( arr ), std::end( arr ),
    []( const auto &a, const auto &b )
    {
        return a != 0 && b != 0 ? a < b : a != 0;
    } );

这里有一个演示功能

#include <iostream>
#include <iterator>
#include <algorithm>

int main()
{
    int arr[] = { 0,3,0,12,1 };
    //std::stable_partition( std::begin( arr ), std::end( arr ), 
    //  []( const auto &x ) { return x != 0; } );

    std::sort( std::begin( arr ), std::end( arr ),
        []( const auto &a, const auto &b )
        {
            return a != 0 && b != 0 ? a < b : a != 0;
        } );

    for (int i : arr) {
        std::cout << i << ' ';
    }
    std::cout << '\n';
}

程序输出为
或者,如果你愿意,你可以写一个单独的比较函数来代替lambda表达式

bool cmp( int a, int b )
{
    return a != 0 && b != 0 ? a < b : a != 0;
}

在本例中,std::sort的调用如下所示:

std::sort( std::begin( arr ), std::end( arr ), cmp );
k4ymrczo

k4ymrczo2#

传递给std::sort的比较器需要是strict weak order。特别是,对于相同的值,您需要cmp(x, x) = false,并且cmp(x, y)cmp(y, x)中最多有一个为真(对于cmp(1, 2) == cmp(2, 1) == true,这不是真)
你想要的是在你的订单中所有元素都是相等的,除了0,它大于所有其他元素。这可以用这样的函数来完成:

bool cmp(int a, int b) {
    if (a == 0) {
        if (b == 0) return false;  // equal
        return false;  // a is greater
    }
    if (b == 0) return true;  // `a < 0`? True, since 0 is the greatest element
    return false;  // All other elements are equivalent, not less than
}

// Simplified to
bool cmp(int a, int b) {
    return b == 0 && a != 0;
}

然后你想使用std::stable_sort来保持等价元素的顺序。
然而,排序并不是最好的方法。你可以简单地将所有非零元素向前移动,然后用0填充后面的空格:

void move_zeroes_to_back(int* begin, int* end) {
    int* nonzero_begin = begin;
    for (; begin != end; ++begin) {
        if (*begin != 0) *nonzero_begin++ = *begin;
        // else Don't move zero values forward
    }
    // Fill in the rest
    for (; nonzero_begin != end; ++nonzero_begin) {
        *nonzero_begin = 0;
    }
}

这个算法的第一部分是std::remove所做的:

void move_zeroes_to_back(int* begin, int* end) {
    int* nonzero_end = std::remove(begin, end, 0);  // Remove all zero values
    std::fill(nonzero_end, end, 0);  // Replace removed zero values at the end
}

相关问题