You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用类std::sort算法跟踪排列奇偶性且无需重实现排序?

跟踪std::sort排列奇偶性的实用方案

std::sort及相关STL算法是C++的核心工具,但在数值线性代数场景中,**跟踪排序对应的排列奇偶性(偶/奇置换)**是一个常见需求——而你提到的三种方法都有明显缺陷,这里提供两种无需重写排序的可行方案:

方案一:代理对象+自定义Swap统计交换次数

通过包装元素的代理类,在排序过程中捕获每一次交换操作,统计交换次数后即可通过模2运算得到排列奇偶性(一次交换对应一个对换,改变奇偶性)。

实现代码

#include <algorithm>
#include <vector>

template <typename T>
class SwapTracker {
public:
    SwapTracker(T& elem, int& counter) : elem_(elem), swap_counter_(counter) {}

    // 转发比较操作到原始元素
    bool operator<(const SwapTracker& other) const {
        return elem_ < other.elem_;
    }

    // 转发赋值操作
    SwapTracker& operator=(const SwapTracker& other) {
        elem_ = other.elem_;
        return *this;
    }

    // 暴露原始元素引用(可选)
    T& get() { return elem_; }
    const T& get() const { return elem_; }

private:
    T& elem_;
    int& swap_counter_;

    // 自定义swap,统计交换次数
    friend void swap(SwapTracker a, SwapTracker b) {
        using std::swap;
        swap(a.elem_, b.elem_);
        // 一次swap对应一次对换,计数器加1
        a.swap_counter_++;
    }
};

int main() {
    std::vector<int> data = {5, 2, 9, 1, 5, 6};
    int swap_count = 0;

    // 构建代理序列
    std::vector<SwapTracker<int>> trackers;
    trackers.reserve(data.size());
    for (auto& num : data) {
        trackers.emplace_back(num, swap_count);
    }

    // 执行排序
    std::sort(trackers.begin(), trackers.end());

    // 计算奇偶性:偶置换返回1,奇置换返回-1
    int perm_sign = (swap_count % 2 == 0) ? 1 : -1;
    return 0;
}

注意事项

  • 不同STL实现的std::sort可能用旋转等操作代替多次交换,但旋转操作的奇偶性等价于对应交换次数的奇偶性,因此结果依然可靠。
  • 确保swap函数只在每次实际元素交换时递增计数器一次,避免重复计数。

方案二:基于索引序列的置换奇偶性计算

这种方法不干扰排序过程,而是通过排序后的索引映射直接计算置换的奇偶性,可靠性更高(不依赖排序实现细节)。

实现代码

#include <algorithm>
#include <vector>

// 计算置换的符号:1为偶置换,-1为奇置换
int permutation_sign(const std::vector<int>& perm) {
    int n = perm.size();
    std::vector<bool> visited(n, false);
    int cycle_count = 0;

    // 分解置换的循环
    for (int i = 0; i < n; ++i) {
        if (!visited[i]) {
            cycle_count++;
            int j = i;
            while (!visited[j]) {
                visited[j] = true;
                j = perm[j];
            }
        }
    }

    // 总对换次数 = 元素总数 - 循环数,模2后决定符号
    return (n - cycle_count) % 2 == 0 ? 1 : -1;
}

int main() {
    std::vector<int> data = {5, 2, 9, 1, 5, 6};
    std::vector<int> indices(data.size());
    // 初始化索引序列
    for (int i = 0; i < data.size(); ++i) {
        indices[i] = i;
    }

    // 按原始元素排序索引
    std::sort(indices.begin(), indices.end(), [&data](int a, int b) {
        return data[a] < data[b];
    });

    // 计算排列符号
    int sign = permutation_sign(indices);
    return 0;
}

优势

  • 完全不修改原始排序逻辑,适用于无法包装元素的场景。
  • 直接从最终置换结果计算奇偶性,不受STL排序实现的影响,结果更稳定。

内容的提问来源于stack exchange,提问作者alfC

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 02:05:46