首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

C++ 結構體陣列多鍵值排序:比較器實作指南

     編輯:程式設計疑難解答

問題背景

使用 C++ 標準庫函式(如 qsort 或 std::sort)對結構體陣列進行多欄位排序時,若直接傳遞單一比較函數指標,難以處理「先按欄位 A 排序,相同再按欄位 B 排序」的邏輯,導致排序結果錯亂。

核心解法:自訂比較器

關鍵在於編寫一個複合比較函數,在單一比較邏輯中依序判斷多個欄位。此函數作為排序演算法的比較器參數傳入。

使用 qsort(C 風格)

#include <stdlib.h>
#include <string.h>

typedef struct {
    int field1;
    int field2;
    char name[32];
} Record;

int compare_records(const void *a, const void *b) {
    const Record *ra = (const Record *)a;
    const Record *rb = (const Record *)b;

    // 第一優先級:field1 遞增
    if (ra->field1 != rb->field1)
        return ra->field1 - rb->field1;

    // 第二優先級:field2 遞減
    if (ra->field2 != rb->field2)
        return rb->field2 - ra->field2; // 反向

    // 第三優先級:name 字典序
    return strcmp(ra->name, rb->name);
}

// 呼叫
qsort(array, count, sizeof(Record), compare_records);

使用 std::sort(C++ 風格,推薦)

#include <algorithm>
#include <vector>
#include <string>

struct Record {
    int field1;
    int field2;
    std::string name;
};

bool compare_records(const Record& a, const Record& b) {
    if (a.field1 != b.field1) return a.field1 < b.field1;      // 遞增
    if (a.field2 != b.field2) return a.field2 > b.field2;      // 遞減
    return a.name < b.name;                                    // 字典序
}

// 呼叫
std::vector vec = ...;
std::sort(vec.begin(), vec.end(), compare_records);

C++11 Lambda 寫法(更簡潔)

std::sort(vec.begin(), vec.end(), [](const Record& a, const Record& b) {
    if (a.field1 != b.field1) return a.field1 < b.field1;
    if (a.field2 != b.field2) return a.field2 > b.field2;
    return a.name < b.name;
});

避免常見錯誤

  • 減法溢位:整數比較若用 a - b 可能溢位,建議用 (a > b) - (a < b) 或三元運算子。
  • 嚴格弱序:比較函數必須滿足傳遞性、反對稱性等嚴格弱序要求,否則 std::sort 行為未定義。
  • 浮點數比較:避免直接用 ==,需設定容差 epsilon。

參考資源

更多範例可參考:CSDN 部落格:C++ 結構體多欄位排序

總結

C++ 結構體陣列多鍵值排序的核心是編寫複合比較器,在單一函數中依優先級順序判斷各欄位。推薦使用 std::sort 搭配 Lambda,型別安全且效能優於 qsort。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved