欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++中的sort與自定義排序詳解

 更新時(shí)間:2025年08月27日 09:02:05   作者:oymaster  
std::sort是C++模板函數(shù),采用內(nèi)省排序(混合快速、堆、插入排序)動(dòng)態(tài)優(yōu)化性能,確保O(nlogn)效率與魯棒性,通過比較器、Lambda或重載運(yùn)算符實(shí)現(xiàn)自定義排序邏輯

基本使用與原理

std::sort 是一個(gè)模板函數(shù),常見簽名如下:

template<class RandomIt>
void sort(RandomIt first, RandomIt last);

template<class RandomIt, class Compare>
void sort(RandomIt first, RandomIt last, Compare comp);
  • first,last:指定排序范圍的隨機(jī)訪問迭代器。
  • comp:可選的比較器,定義元素順序,默認(rèn)為 std::less(基于 operator< 的升序排序)。
  • 時(shí)間復(fù)雜度:平均和最壞情況均為 O(n log n)。
  • 空間復(fù)雜度:通常為 O(log n),用于遞歸棧或臨時(shí)緩沖區(qū)。
  • 要求:比較器必須滿足嚴(yán)格弱序(strict weak ordering),否則可能導(dǎo)致未定義行為。

核心算法:內(nèi)省排序(Introsort)

C++ 標(biāo)準(zhǔn)未強(qiáng)制指定 std::sort 的實(shí)現(xiàn)算法,但大多數(shù)現(xiàn)代標(biāo)準(zhǔn)庫(kù)(如 libstdc++、libc++)采用 內(nèi)省排序(Introsort)。

Introsort 由 David Musser 于 1997 年提出,是一種混合排序算法,結(jié)合了快速排序(Quicksort)、堆排序(Heapsort)和插入排序(Insertion Sort)的優(yōu)點(diǎn),以兼顧效率和魯棒性。

1. 快速排序

快速排序是 Introsort 的主要算法,步驟如下:

  • 選擇基準(zhǔn)(pivot):通常使用三數(shù)取中(median-of-three,選取首、尾、中間元素的中位數(shù))或隨機(jī)選擇。
  • 分區(qū)(partition):將元素分為小于等于基準(zhǔn)和大于基準(zhǔn)的兩部分。
  • 遞歸:對(duì)兩個(gè)子區(qū)間遞歸排序。

特點(diǎn)

  • 平均時(shí)間復(fù)雜度:O(n log n)。
  • 最壞情況(如已排序或逆序數(shù)組):O(n²)。
  • 優(yōu)化:三數(shù)取中或隨機(jī)化基準(zhǔn)減少最壞情況概率。

實(shí)現(xiàn)細(xì)節(jié)

  • 分區(qū)方案:常用 Lomuto 或 Hoare 分區(qū)算法。
  • 基準(zhǔn)選擇:三數(shù)取中避免極端情況(如已排序輸入)。

2. 堆排序

當(dāng)快速排序的遞歸深度超過閾值(通常為 2 * log n),Introsort 切換到堆排序,以避免快速排序的最壞情況。

步驟

  • 構(gòu)建最大堆(或最小堆,取決于排序順序)。
  • 反復(fù)將堆頂元素移到末尾并調(diào)整堆。

特點(diǎn)

  • 時(shí)間復(fù)雜度:始終為 O(n log n)。
  • 空間復(fù)雜度:O(1)(原地排序)。
  • 適合處理快速排序退化的場(chǎng)景。

實(shí)現(xiàn)細(xì)節(jié)

  • 使用數(shù)組表示堆,通過下標(biāo)計(jì)算父子節(jié)點(diǎn)關(guān)系。
  • 堆調(diào)整(sift-down)確保堆性質(zhì)。

3. 插入排序

當(dāng)子區(qū)間大小較小時(shí)(通常 < 16 或 32 個(gè)元素,具體閾值依實(shí)現(xiàn)而定),Introsort 切換到插入排序。

步驟

  • 逐個(gè)將元素插入到已排序的子序列中。

特點(diǎn)

  • 時(shí)間復(fù)雜度:O(n²),但在小數(shù)組上常數(shù)開銷低。
  • 適合部分有序或小規(guī)模數(shù)據(jù)。

實(shí)現(xiàn)細(xì)節(jié)

  • 通常通過循環(huán)實(shí)現(xiàn),避免遞歸。
  • 常用于優(yōu)化小規(guī)模子區(qū)間的排序。

原因:

  • 快速排序:平均性能優(yōu)異,但在最壞情況下(如已排序或重復(fù)元素)退化為 O(n²)。
  • 堆排序:保證最壞情況 O(n log n),但平均性能稍遜,且堆調(diào)整開銷較高。
  • 插入排序:在小規(guī)模數(shù)據(jù)上高效,減少遞歸開銷。 Introsort 動(dòng)態(tài)切換算法,確保:
  • 高效性:利用快速排序的平均性能。
  • 魯棒性:通過堆排序避免最壞情況。
  • 優(yōu)化性:插入排序處理小數(shù)組。

自定義排序

1. 函數(shù)指針

定義一個(gè)獨(dú)立的比較函數(shù),簽名需為bool(T, T)

bool compare(int a, int b) {
    return a > b; // 降序排序
}

std::vector<int> vec = {5, 2, 9, 1, 5};
std::sort(vec.begin(), vec.end(), compare); // 結(jié)果為 {9, 5, 5, 2, 1}

2. 靜態(tài)成員函數(shù)

在類中定義靜態(tài)比較函數(shù),避免依賴對(duì)象實(shí)例:

class Sorter {
public:
    static bool compare(int a, int b) {
        return a > b; // 降序排序
    }
};

std::vector<int> vec = {5, 2, 9, 1, 5};
std::sort(vec.begin(), vec.end(), Sorter::compare);

注意:非靜態(tài)成員函數(shù)因隱含this指針,簽名不匹配std::sort的要求,因此無法直接使用。

3. 使用函數(shù)對(duì)象

通過定義一個(gè)類并重載operator(),可以在比較器中存儲(chǔ)狀態(tài):

class Comparator {
    int threshold;
public:
    Comparator(int t) : threshold(t) {}
    bool operator()(int a, int b) const {
        return a > threshold && a < b; // 僅對(duì)大于threshold的元素降序排序
    }
};

std::vector<int> vec = {5, 2, 9, 1, 5};
std::sort(vec.begin(), vec.end(), Comparator(3));

4. 使用Lambda表達(dá)式(C++11及以上)

Lambda表達(dá)式提供了一種簡(jiǎn)潔的方式定義比較器,并可捕獲外部變量:

int threshold = 3;
std::vector<int> vec = {5, 2, 9, 1, 5};
std::sort(vec.begin(), vec.end(), [threshold](int a, int b) {
    return a > threshold && a < b;
});

5.使用std::function

C++11引入的std::function可以包裝任何可調(diào)用對(duì)象(包括函數(shù)指針、Lambda、函數(shù)對(duì)象等),提供更靈活的方式:

#include <functional>
std::function<bool(int, int)> comp = [](int a, int b) {
    return a > b; // 降序排序
};

std::vector<int> vec = {5, 2, 9, 1, 5};
std::sort(vec.begin(), vec.end(), comp);

適用場(chǎng)景:當(dāng)需要在運(yùn)行時(shí)動(dòng)態(tài)選擇比較器時(shí),std::function非常有用,但會(huì)引入少量性能開銷。

6.使用標(biāo)準(zhǔn)比較器(如std::greater、std::less)

C++標(biāo)準(zhǔn)庫(kù)提供了預(yù)定義的比較器(如<functional>中的std::greaterstd::less),可直接用于簡(jiǎn)單排序需求:

#include <functional>
std::vector<int> vec = {5, 2, 9, 1, 5};
std::sort(vec.begin(), vec.end(), std::greater<int>()); // 降序排序
std::sort(vec.begin(), vec.end(), std::less<int>());   // 升序排序

優(yōu)點(diǎn):無需手動(dòng)定義比較器,代碼簡(jiǎn)潔,適合常見升序或降序需求。

7.重載operator<

對(duì)于自定義結(jié)構(gòu)體或類,可以通過重載operator<來定義默認(rèn)排序規(guī)則,省去顯式比較器:

struct Person {
    std::string name;
    int age;
    bool operator<(const Person& other) const {
        return age < other.age; // 按年齡升序
    }
};

std::vector<Person> people = {{"Alice", 25}, {"Bob", 30}, {"Charlie", 20}};
std::sort(people.begin(), people.end()); // 使用operator<,按年齡升序

適用場(chǎng)景:當(dāng)類型有自然的排序規(guī)則且不需要多種排序方式時(shí),重載operator<是最簡(jiǎn)潔的方案。

自定義結(jié)構(gòu)體或類的排序

當(dāng)排序?qū)ο笫亲远x結(jié)構(gòu)體或類時(shí),可以結(jié)合上述方法。

例如,使用Lambda:

std::vector<Person> people = {{"Alice", 25}, {"Bob", 30}, {"Charlie", 20}};

// 按名字字典序排序
std::sort(people.begin(), people.end(), [](const Person& a, const Person& b) {
    return a.name < b.name;
});

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論