最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++ STL 進階:手寫 priority_ueue 與仿函數(shù)機制詳解

 更新時間:2026年05月25日 09:30:06   作者:Zhang~Ling  
本文介紹了C++標準庫中的priority_queue(優(yōu)先級隊列)及其實現(xiàn)原理,同時通過代碼示例展示了仿函數(shù)在排序算法和條件判斷中的實際應用,感興趣的朋友一起看看吧

1. 引言:什么是priority_queue

1.1 基本概念

priority_queue 是 C++ 標準庫中的一個容器適配器。它提供的是一種優(yōu)先級隊列的數(shù)據(jù)結構語義:

  • 插入元素的時間復雜度為 O(log N)
  • 刪除元素的時間復雜度為 O(log N)
  • 獲取最高優(yōu)先級元素的時間復雜度為 O(1)
  • 核心特性:每次 pop 出來的,都是當前隊列中優(yōu)先級最高的元素。

1.2 底層結構

priority_queue底層默認使用std::vector作為容器,并在其之上維護一個堆結構:

  • 大堆:父節(jié)點 ≥ 子節(jié)點 → top() 返回最大值
  • 小堆:父節(jié)點 ≤ 子節(jié)點 → top() 返回最小值
    堆的性質通過兩個核心操作來維護:向上調整(插入時)向下調整(刪除時)。
    但是priority_queue是反過來的:
    默認傳小于less仿函數(shù),大的優(yōu)先級高;傳大于greater仿函數(shù),小的優(yōu)先級高。因此我們在實現(xiàn)的過程中也要依照次風格。

1.3 比較器的默認行為

priority_queue 有一個可選的模板參數(shù) Compare,用于定義元素之間的優(yōu)先級比較規(guī)則:

  • 如果不顯式提供,默認使用 std::less<T>
  • std::less<T> 是一個仿函數(shù),內部調用 operator<
  • 在默認 std::less 下,priority_queue 表現(xiàn)為大堆(最大值在堆頂)

如果你需要小堆,可以顯式傳入 std::greater<T> 或自定義仿函數(shù)。

注意:比較器不是“必須寫的”,它有默認行為。 是否顯式提供,取決于你是否需要改變默認的排序規(guī)則。我們下面會對比較器進行顯示構造來演示仿函數(shù)和比較器的行為。

2. priority_queue的核心實現(xiàn)

2.1 成員變量與默認構造

2.1.1 結構框架與默認構造

template<class T, class Container = vector<T>, class Compare = Less<T>>
//Container,Compare 是我們對庫里面的結構進行了顯示構造便于我們理解底層結構
class priority_queue {
public:
    priority_queue() = default;  // 編譯器生成默認構造
private:
    Container _con;               // 底層容器
};

這里引出Container,Compare我們下面的章節(jié)進行詳細的解釋

2.1.2 迭代器區(qū)間構造

構造結構:

template<class InputIterator>
priority_queue(InputIterator first, InputIterator last)
	:_con(first, last)
{
	//給一個迭代器區(qū)間構造優(yōu)先隊列的底層是堆結構
	//向下調整建隊構造
	for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--) {
		adjust_down(i);
	}
}

因為存儲底層結構是vector,邏輯結構是堆,所以說我們在構造的過程中就涉及到了建堆:(我們選擇向下調整建堆,時間效率比向上建隊高,具體原因這里不做闡述)
建堆時間復雜度O(N)。
向下調整算法:

void adjust_down(size_t parent) {
	Compare com;
	size_t child = parent * 2 + 1;
	while (child < _con.size()) {
		if (child + 1 < _con.size() && com(_con[child], _con[child + 1])) {
			child++;
		}
		// 如果 父節(jié)點優(yōu)先級 < 孩子節(jié)點優(yōu)先級,則交換
		// 在大堆中:parent < child -> com(parent, child) 為 true -> 交換
		// 在小堆中:parent > child -> com(parent, child) 為 true -> 交換
		if (com(_con[parent], _con[child])) {
			swap(_con[parent], _con[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else {
			break;
		}
	}
}

2.2 push插入數(shù)據(jù)

push邏輯:

void push(const T& x) {
    _con.push_back(x);
    adjust_up(_con.size() - 1);
}

插入數(shù)據(jù)并且需要維持堆結構,我們需要將插入的數(shù)據(jù)進行向上調整:

void adjust_up(size_t child) {
	Compare com;
	size_t parent = (child - 1) / 2;
	while (child > 0) {
		//if (_con[parent] < _con[child])
		if(com(_con[parent],_con[child])){
			swap(_con[parent], _con[child]);//調用的庫里面的函數(shù)
			child = parent;
			parent = (child - 1) / 2;
		}
		else {
			break;
		}
	}
}

2.3 pop刪除數(shù)據(jù)

void pop() {
	assert(!empty());
    std::swap(_con[0], _con[_con.size() - 1]);
    _con.pop_back();
    adjust_down(0);
}

2.4 top / empty / size

const T& top() const { return _con[0]; }
bool empty() const { return _con.empty(); }
size_t size() const { return _con.size(); }

對于上述的底層構造我們引出適配器模式和仿函數(shù)的使用,下面我們來詳細解釋一下??????

3. 適配器模式與priori_queue的設計

3.1 什么是適配器模式

適配器模式:把一個已有的東西包裝一下,換個接口或者行為再使用。
(實際上就像手機充電線一樣,有不同的接口來適配不同的手機。)
容器適配器:把底層容器包裝成另一種數(shù)據(jù)結構。在這里說人話也就是將容器類型引入到模板里面,讓你可以任意調用已有的底層容器的接口。

3.2 priority_queue的適配器設計

也就是:

template<class T, class Container = vector<T>, class Compare = Less<T>>
//Container讓我們可以很輕松的更改priority_queue的底層存儲邏輯
//這里只是給一個缺省值我們可以顯示給的
class priority_queue {
    Container _con;
};
  • Container:底層容器類型(默認 vector<T>
  • Compare:比較仿函數(shù)類型(默認 Less<T>,對應大堆)
    意義:模板適配器參數(shù)的缺省值讓用戶在使用時更簡潔,同時保留了高度可定制性

4. 仿函數(shù)

4.1 什么是仿函數(shù)

仿函數(shù)實際上就是將operator()進行了重載,讓類和結構體可以像函數(shù)一樣被調用。
仿函數(shù)的定義:

template<class T>
class Less {
public:
	bool operator()(const T& x, const T& y) {
		return x < y;
	}
};
template<class T>
class Greater {
public:
	bool operator()(const T& x, const T& y) {
		return x > y;
	}
};

4.2 仿函數(shù)的用法

4.2.1 作為比較器,控制容器或者算法的行為

實際上就是將容器的規(guī)則或者算法的規(guī)則作為參數(shù)傳入,讓容器或者算法的行為可以定制。
代碼示例1:

int main() {
//默認使用 Less → 大堆
	ZL::priority_queue<int> pq1;
//顯示指定Greater->建大堆
	ZL::priority_queue<int, vector<int>, Greater<int>> pq2;
	pq1.push(100);
	pq1.push(5);
	pq1.push(200);
	pq1.push(10);
	while (!pq1.empty()) {
		cout << pq1.top() << " ";
		pq1.pop();
	}
	return 0;
}

示例代碼2:

template<class T, class Compare>
void BubbleSort(T* a, int n, Compare com) {
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n - i - 1; ++j) {
            if (com(a[j + 1], a[j]))   // 比較規(guī)則由仿函數(shù)決定
                swap(a[j], a[j + 1]);
        }
    }
}
int main() {
	int a[] = { 1,3,4,5,6,3,2 };
	//讓類可以像函數(shù)一樣調用
	BubbleSort(a, 7, Less<int>());//排升序
	BubbleSort(a, 7, Greater<int>());//排降序
	for (auto ch : a) {
		cout << ch;//自動迭代不用++
	}
	cout << endl;
}

解釋一下該過程:

4.2.2 作為判斷條件或者作為轉換規(guī)則

示例代碼1:查找第一個偶數(shù)(作為判斷條件)

struct OP1 {
	bool operator()(int x) {
		return x % 2 == 0;
	}
};
int main() {
	int a[] = { 1,3,2,9,1,3,4,5 };
	//查找第一個偶數(shù)
	auto it = find_if(a, a + 7, OP1());
	cout << *it << endl
	return 0;
}

示例代碼2:將偶數(shù)都乘二(作為轉換條件)

struct OP2 {
		int operator()(int x) {
			if (x % 2 == 0)
				return x * 2;
			else
				return x;
		}

};
int main() {
	//transform 是 C++ 標準庫中的一個算法,用于對容器中的每個元素執(zhí)行某種操作,并將結果存儲到另一個位置。
	//它屬于 <algorithm> 頭文件。
	transform(v.begin(), v.end(), v.begin(), OP2());
	for (auto& e : v) {
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

4.2.3 處理指針時自定義比較邏輯

下面截取日期代碼的一部分做演示:

//struct PDateLess
//{
//	bool operator()(const Date* p1, const Date* p2)//仿函數(shù)
//	{
//	return *p1 < *p2;//這里能直接對存儲地址解引用對比出誰的日期大是因為
//在日期結構體中對<運算符進行了重載
//	}
int main() {
	ZL::priority_queue<Date*, vector<Date*>, PDateLess> q1;
	q1.push(new Date(2018, 10, 29));
	q1.push(new Date(2018, 10, 28));
	q1.push(new Date(2018, 10, 30));
	while (!q1.empty()) {
		cout << *q1.top() << " ";
		q1.pop();
	}
	cout << endl;
	return 0;
}

這里自定義仿函數(shù)的原因是:指針的默認比較是按地址大小,而不是按 Date 對象的內容。通過仿函數(shù)可以“糾正”這個行為(也就是解引用獲得存儲在該地址里的內容)。

4.3 仿函數(shù)存在的意義

仿函數(shù)的存在實際上是C++想要摒棄函數(shù)指針的使用,仿函數(shù)提供了比函數(shù)指針更優(yōu)的替代方案,在現(xiàn)代 C++ 中優(yōu)先推薦使用仿函數(shù)或 lambda。

問題沒有仿函數(shù)時的痛點有仿函數(shù)時的解決方式
算法需要多種行為寫多個函數(shù)或用函數(shù)指針,效率低且不能內聯(lián)把行為封裝成仿函數(shù),編譯期內聯(lián),無額外開銷
需要攜帶狀態(tài)函數(shù)無法記住之前的調用信息仿函數(shù)可以有成員變量,在多次調用間保持狀態(tài)
類型安全函數(shù)指針類型檢查弱,容易傳錯仿函數(shù)作為類類型,類型檢查更嚴格
與模板結合函數(shù)指針作為模板參數(shù)不自然仿函數(shù)是類型,作為模板參數(shù)使用方便
復雜規(guī)則封裝難以復用一個仿函數(shù)類可以在多個地方復用

到此這篇關于C++ STL 進階:手寫 priority_ueue 與仿函數(shù)機制詳解的文章就介紹到這了,更多相關C++ priority_ueue 與仿函數(shù)機制內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 關于C++菱形運算符深度解析

    關于C++菱形運算符深度解析

    從語言標準來說,c++里沒有什么菱形運算符,c++20里雖然新增了一個運算符operator<=>,但這個和所謂的菱形運算符沒有任何關系,下面通過本文探討C++里也有菱形運算符嗎這一問題探討,感興趣的朋友跟隨小編一起看看吧
    2024-04-04
  • 匯編語言常見錯誤信息中文注解

    匯編語言常見錯誤信息中文注解

    這篇文章主要介紹了匯編語言常見錯誤信息中文注解,本文收集大部分匯編中常見錯誤信息及對應的中文注解,需要的朋友可以參考下
    2014-09-09
  • VS2010/MFC編程(常用控件:樹形控件Tree Control控件創(chuàng)建h和實例)

    VS2010/MFC編程(常用控件:樹形控件Tree Control控件創(chuàng)建h和實例)

    本篇文章介紹了VS2010/MFC編程:常用控件:樹形控件Tree Control,包括樹形控件的創(chuàng)建、CTreeCtrl類的主要成員函數(shù)和應用實例有興趣的可以了解一下。
    2016-12-12
  • 減少C++代碼編譯時間的簡單方法(必看篇)

    減少C++代碼編譯時間的簡單方法(必看篇)

    下面小編就為大家?guī)硪黄獪p少C++代碼編譯時間的簡單方法(必看篇)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • Qt實現(xiàn)棋盤游戲

    Qt實現(xiàn)棋盤游戲

    這篇文章主要為大家詳細介紹了Qt實現(xiàn)棋盤游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C語言實現(xiàn)學生信息管理系統(tǒng)開發(fā)

    C語言實現(xiàn)學生信息管理系統(tǒng)開發(fā)

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)學生信息管理系統(tǒng)開發(fā),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • C語言memset函數(shù)詳解

    C語言memset函數(shù)詳解

    這篇文章主要介紹了C語言中的memset()函數(shù),包括其與memcpy()函數(shù)的區(qū)別,需要的朋友可以參考下,希望能夠給你帶來幫助
    2021-09-09
  • C++關于引用作為函數(shù)的用法

    C++關于引用作為函數(shù)的用法

    今天小編就為大家分享一篇關于C++關于引用作為函數(shù)的用法,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • C++中typeid實現(xiàn)原理詳解

    C++中typeid實現(xiàn)原理詳解

    這篇文章主要給大家介紹了關于C++中typeid實現(xiàn)原理的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-11-11
  • C++實現(xiàn)LeetCode(65.驗證數(shù)字)

    C++實現(xiàn)LeetCode(65.驗證數(shù)字)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(65.驗證數(shù)字),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下
    2021-07-07

最新評論

昌都县| 武威市| 南乐县| 洛浦县| 沧源| 永泰县| 温宿县| 彭水| 五常市| 安阳市| 石阡县| 迁安市| 论坛| 新巴尔虎左旗| 三原县| 汉阴县| 阿克苏市| 静海县| 沁水县| 平山县| 墨竹工卡县| 靖江市| 龙游县| 蒙城县| 景德镇市| 绥滨县| 琼结县| 穆棱市| 吴忠市| 贵港市| 南郑县| 八宿县| 建宁县| 磴口县| 邯郸市| 禹州市| 乌兰县| 湛江市| 绩溪县| 海南省| 金寨县|