C語言八大排序之堆排序
前言
本章我們來講解八大排序之堆排序。2022,地球Online新賽季開始了!讓我們一起努力內(nèi)卷吧!
一、堆排序的概念
?? 堆排序(Heapsort):利用堆積樹(堆)這種數(shù)據(jù)結(jié)構(gòu)所設(shè)計(jì)的一種排序算法,它是選擇排序的一種。通過堆來進(jìn)行選擇數(shù)據(jù),需要注意的是 排升序要建大堆,排降序建小堆。
堆排序使用堆來選數(shù),效率就高了很多。
- 時(shí)間復(fù)雜度:
- 空間復(fù)雜度:
- 穩(wěn)定性:不穩(wěn)定
二、堆排序的實(shí)現(xiàn)
我們先創(chuàng)建一個(gè)堆排序的函數(shù):
void HeapSort(int arr[], int n);
假設(shè)我們要對(duì)下列數(shù)組來使用堆排序(升序):
int arr[] = {70, 56, 30, 25, 15, 10, 75};
根據(jù)我們之前學(xué)到的知識(shí),數(shù)組是可以直接看作為完全二叉樹的,所以我們可以把它化為堆。此時(shí)我們就可以 "選數(shù)" (堆排序本質(zhì)上是一種選擇排序)。
第一步:構(gòu)建堆
第一步就是要想辦法把 arr 數(shù)組構(gòu)建成堆(這里我們先構(gòu)建成小堆)。我們介紹兩種方法,分別為向上調(diào)整算法和向下調(diào)整算法:
方法1:向上調(diào)整
通過我們之前學(xué)過的 "向上調(diào)整" ,利用插入的思路來解決。首先設(shè)計(jì)下向上調(diào)整的算法:
void Swap(HPDataType* px, HPDataType* py) { HPDataType tmp = *px; *px = *py; *py = tmp; } /* 小堆的向上調(diào)整 */ void AdjustUp(int* arr, int child) { assert(arr); // 首先根據(jù)公式計(jì)算算出父親的下標(biāo) int parent = (child - 1) / 2; // 最壞情況:調(diào)到根,child=parent 當(dāng)child為根節(jié)點(diǎn)時(shí)結(jié)束(根節(jié)點(diǎn)永遠(yuǎn)是0) while(child > 0) { if(arr[child] < arr[parent]) { // 如果孩子小于父親(不符合小堆的性質(zhì)) // 交換他們的值 Swap(&arr[child],&arr[parent]); // 傳地址 // 往上走 child = parent; parent = (child - 1) / 2; } else { // 如果孩子大于父親(符合小堆的性質(zhì)) // 跳出循環(huán) break; } } }
① 首先,通過公式計(jì)算出父親的下標(biāo),公式如下:
② 其次,設(shè)計(jì)循環(huán)部分,最壞情況為調(diào)到根,如果已經(jīng)符合大堆的條件則終止循環(huán)。
③ 進(jìn)入循環(huán)后進(jìn)行判斷,如果 child > parent,則交換它們的值,讓父親獲得孩子的值,孩子得到父親的值,從而讓它們符合大堆的性質(zhì)。
④ 交換完畢后,以便于繼續(xù)判斷,我們需要更新 child 和 parent 指向的元素,做到 "往上走"
此時(shí),我們把數(shù)組里的元素依次調(diào)整即可。
?? 方法1:
/* 升序 */ void HeapSort(int arr[], int n) { for (int i = 1; i < n; i++) { AdjustUp(arr, i); // 傳入數(shù)組 和 child的下標(biāo) } }
我們不需要從 0 開始調(diào),從 1 開始調(diào)。所以 i 的起始值設(shè)置為 1 。此時(shí),小堆就構(gòu)建好了。
方法2:向下調(diào)整
向下調(diào)整算法我們?cè)诙涯莻€(gè)章節(jié)也學(xué)過了,這里我們?cè)賮韽?fù)習(xí)一下:
void SmallAjustDown(int* arr, int n, int parent) { int child = parent * 2 + 1; // 默認(rèn)為左孩子 while(child < n) { // 葉子內(nèi) // 選出左右孩子中小的那一個(gè) if(child + 1 < n && arr[child + 1] < arr[child]) { child = child + 1; } // 如果孩子小于父親(不符合小堆的性質(zhì)) if(arr[child] < arr[parent]) { // 交換它們的值 Swap(&arr[child], &arr[parent]); // 往下走 parent = child; child = parent * 2 + 1; } else { // 如果孩子大于父親(符合小堆的性質(zhì)) // 跳出循環(huán) break; } } }
① 因?yàn)橐紤]左孩子還是右孩子,我們可以定義兩個(gè)變量,分別記錄左孩子和有孩子。但是我們這里可以用更好的方法,只需要定義一個(gè)孩子即可。具體實(shí)現(xiàn)方法如下:首先創(chuàng)建 child,我們先默認(rèn)它是左孩子,利用傳進(jìn)來的 parent 根據(jù)公式計(jì)算出 child 的大小:
因?yàn)槲覀儠呵夷J(rèn)為左孩子,我們隨后進(jìn)入循環(huán)后要進(jìn)行檢查,看看是左孩子大還是右孩子大,這里我們只需要根據(jù)數(shù)組的性質(zhì),將 child + 1 即可得到右孩子的下標(biāo),從而方便我們進(jìn)行比較。比較完畢后將 child 重新賦值,拿個(gè)孩子小就將 child 給誰。
② 一共有兩個(gè)結(jié)束條件(出口),第一個(gè)結(jié)束條件是父親小于孩子就停止,第二個(gè)結(jié)束條件是chi調(diào)整到葉子。所以,循環(huán)體判斷部分根據(jù)我們分析的結(jié)束條件,如果調(diào)整到葉子就結(jié)束,我們接受了 n,也就是數(shù)組的大小,只要 child 超過數(shù)組的大?。╟hild > n) 就結(jié)束,這是第一個(gè)出口。
③ 進(jìn)入循環(huán)后,對(duì)比左孩子和右孩子哪一個(gè)更小,child 就交付給誰。這里還要注意的是,要防止孩子不存在的情況,如果 child + 1 比 n 大,就說明孩子不存在。所以我們?cè)賹?if 判斷條件的時(shí)候就要注意了,我們加一個(gè) child + 1 < n 的條件限制一下:
if(child + 1 < n && arr[child + 1] < arr[child]) {...}
④ 確認(rèn)好較小的孩子后,我們就可以開始比較孩子和父親的大小了。如果孩子小于父親,就不符合小堆的性質(zhì),我們就要交換它們的值。這里我們直接調(diào)用我們剛才寫的 Swap 接口即可,這就是為什么在寫向上調(diào)整的時(shí)候要我們單獨(dú)把交換部分的代碼寫成函數(shù)的原因。
⑤ 交換完畢后,他們的值已經(jīng)互相交換好了,這時(shí)我們要改變 parent 和 child 的指向,讓它們往下走,parent = child ,child 再次根據(jù)公式算出新的 child 即可。
⑥ 設(shè)計(jì)下 if 的 else 部分,如果數(shù)組的 child 的值大于 parent 的值,說明符合小堆的性質(zhì)了, break 跳出循環(huán)即可,這是第二個(gè)出口。
向下調(diào)整算法的前提:左右子樹必須都是小堆
如果左子樹和右子樹不是小堆,怎么辦?
可以用遞歸解決,但是我們能用循環(huán)就用循環(huán)來解決:
葉子所在的子樹是不需要調(diào)的。所以,我們從倒著走的第一個(gè)非葉子結(jié)點(diǎn)的子樹開始調(diào)。
(所以我們先調(diào)整30)
為了能夠演示得更明顯,我們?cè)俳o數(shù)組再加點(diǎn)數(shù)據(jù),假設(shè)我們需要對(duì)以下數(shù)組排序:
這里,我們找到了15。
…… 下標(biāo)不斷地 - - 后:
由于,從倒著走的第一個(gè)非葉子結(jié)點(diǎn)的子樹開始調(diào),即,最后一個(gè)節(jié)點(diǎn)的父親。
我們已知最后一個(gè)節(jié)點(diǎn)的下標(biāo)為:
那么,我們可以通過公式計(jì)算出他父親的下標(biāo):
?? 方法2:
/* 升序 */ void HeapSort(int arr[], int n) { for (int i = (n - 1 - 1) / 2; i >= 0; i--) { AdjustDown(arr, n, i); } }
? 這么寫或許可以看得更明白:
/* 升序 */ void HeapSort(int arr[], int sz) { int father = ((sz - 1) - 1) / 2; // 計(jì)算出最后一個(gè)葉子節(jié)點(diǎn)的父親 while (father >= 0) { AdjustDown(arr, sz, father); father--; } }
?? 測(cè)試堆是否創(chuàng)建好了:
我們這里選擇使用方法2。此外,我們剛才實(shí)現(xiàn)的是小堆。
#include <stdio.h> /* 交換函數(shù) */ void Swap(int* px, int* py) { int tmp = *px; *px = *py; *py = tmp; } /* 小堆下調(diào) */ void AdjustDown(int arr[], int sz, int father_idx) { int child_idx = father_idx * 2 + 1; // 計(jì)算出左孩子的值(默認(rèn)認(rèn)為左孩子大) while (child_idx < sz) { // 最壞情況:調(diào)到葉子(child >= 數(shù)組范圍時(shí)必然已經(jīng)調(diào)到葉子) if ((child_idx + 1 < sz) && (arr[child_idx + 1] < arr[child_idx])) { // 如果右孩子存在且右孩子比左孩子小 child_idx = child_idx + 1; // 讓其代表右孩子 } if (arr[child_idx] < arr[father_idx]) { // 如果孩子的值小于父親的值(大符合小堆的性質(zhì)) Swap(&arr[child_idx], &arr[father_idx]); // 交換它們的值 /* 往下走 */ father_idx = child_idx; // 更新下標(biāo) child_idx = father_idx * 2 + 1; // 計(jì)算出該節(jié)點(diǎn)路線的新父親 } else { // 如果孩子的值大于父親的值(符合小堆的性質(zhì)) break; // 終止循環(huán) } } } /* 升序 */ void HeapSort(int arr[], int sz) { /* 創(chuàng)建大堆,選出最大的數(shù) O(N) */ int father = ((sz - 1) - 1) / 2; // 計(jì)算出最后一個(gè)葉子節(jié)點(diǎn)的父親 while (father >= 0) { AdjustDown(arr, sz, father); father--; } } void HeapPrint(int arr[], int sz) { for (int i = 0; i < sz; i++) { printf("%d ", arr[i]); } printf("\n"); } int main(void) { int arr[] = {70, 56, 30, 25, 15, 10, 75, 33, 50, 69}; int sz = sizeof(arr) / sizeof(arr[0]); HeapSort(arr, sz); HeapPrint(arr, sz); return 0; }
?? 運(yùn)行結(jié)果:10 15 30 25 56 70 75 33 50 69
第二步:排序
剛才介紹了兩種方法來構(gòu)建堆,現(xiàn)在堆已經(jīng)構(gòu)建完畢了,我們可以開始設(shè)計(jì)排序部分的算法了。
? 如果排升序,建小堆……
① 選出最小的數(shù),放到第一個(gè)位置,這很簡(jiǎn)單,直接取頂部就可以得到最小的數(shù)。
② 但問題來了,如何選出次小的數(shù)呢?
從 15 開始,剩下的元素看作一個(gè)堆。但是這之前建立好的堆關(guān)系全部亂了!你還得重新建堆,才能選出次小的數(shù)。建堆的時(shí)間復(fù)雜度為 ,需要不斷地建堆
則用小堆的時(shí)間復(fù)雜度就是
,這太離譜了!搞了一大圈結(jié)果居然是
,還不如直接遍歷選出來的方便呢。
建小堆來排升序是完全可以的,但是效率太低!完全沒有體現(xiàn)出你用堆的優(yōu)勢(shì)!
? 解決方法:使用大堆來排升序!
?? 我們剛才已經(jīng)實(shí)現(xiàn)好小堆了,根據(jù)上一節(jié)學(xué)到的知識(shí),小堆要變成大堆,直接把剛才的代碼的 "<" 改成 ">" 即可:
#include <stdio.h> /* 交換函數(shù) */ void Swap(int* px, int* py) { int tmp = *px; *px = *py; *py = tmp; } /* 大堆下調(diào) */ void AdjustDown(int arr[], int sz, int father_idx) { int child_idx = father_idx * 2 + 1; // 計(jì)算出左孩子的值(默認(rèn)認(rèn)為左孩子大) while (child_idx < sz) { // 最壞情況:調(diào)到葉子(child >= 數(shù)組范圍時(shí)必然已經(jīng)調(diào)到葉子) if ((child_idx + 1 < sz) && (arr[child_idx + 1] > arr[child_idx])) { // 如果右孩子存在且右孩子比左孩子大 child_idx = child_idx + 1; // 讓其代表右孩子 } if (arr[child_idx] > arr[father_idx]) { // 如果孩子的值大于父親的值(不符合大堆的性質(zhì)) Swap(&arr[child_idx], &arr[father_idx]); // 交換它們的值 /* 往下走 */ father_idx = child_idx; // 更新下標(biāo) child_idx = father_idx * 2 + 1; // 計(jì)算出該節(jié)點(diǎn)路線的新父親 } else { // 如果孩子的值小于父親的值(符合大堆的性質(zhì)) break; // 終止循環(huán) } } } /* 升序 */ void HeapSort(int arr[], int sz) { /* 創(chuàng)建大堆,選出最大的數(shù) O(N) */ int father = ((sz - 1) - 1) / 2; // 計(jì)算出最后一個(gè)葉子節(jié)點(diǎn)的父親 while (father >= 0) { AdjustDown(arr, sz, father); father--; } } void PrintArray(int arr[], int sz) { for (int i = 0; i < sz; i++) { printf("%d ", arr[i]); } printf("\n"); } int main(void) { int arr[] = {70, 56, 30, 25, 15, 10, 75, 33, 50, 69}; int sz = sizeof(arr) / sizeof(arr[0]); HeapSort(arr, sz); PrintArray(arr, sz); return 0; }
?? 運(yùn)行結(jié)果:75 69 70 50 56 10 30 33 25 15
?? 現(xiàn)在改成了大堆,我們要排升序,我們可以讓堆頂數(shù)和最后的數(shù)進(jìn)行交換:
這并不會(huì)帶來堆結(jié)構(gòu)的破壞!我們把75不看作堆的一部分即可。再進(jìn)行向下調(diào)整,就可以找到次小的數(shù)了。此時(shí)時(shí)間復(fù)雜度為
?? 步驟總結(jié):
① 建大堆,選出最大的數(shù)。
② 最大的數(shù)跟最后一個(gè)數(shù)交換。
③ 如何選出次大的數(shù)呢?把最后一個(gè)數(shù)不看作堆里面,進(jìn)行向下調(diào)整。
?? 代碼實(shí)現(xiàn)(用 while):
/* 堆排序 - 升序 */ void HeapSort(int arr[], int sz) { /* 創(chuàng)建大堆,選出最大的數(shù) O(N) */ int father = ((sz - 1) - 1) / 2; // 計(jì)算出最后一個(gè)葉子節(jié)點(diǎn)的父親 while (father >= 0) { AdjustDown(arr, sz, father); father--; } /* 依次選數(shù),調(diào)堆 O(N * logN) */ int end = sz - 1; while (end > 0) { Swap(&arr[0], &arr[end]); // 最大的數(shù)跟最后一個(gè)數(shù)交換 AdjustDown(arr, end, 0); // 調(diào)堆,選出次大的數(shù) end--; } }
?? 代碼實(shí)現(xiàn)(用 for):
void HeapSort(int arr[], int sz) { /* 建堆 */ for (int father = (sz - 1 - 1) / 2; father >= 0; father--) { AdjustDown(arr, sz, father); } /* 排序 */ for (int end = sz - 1; end > 0; end--) { Swap(&arr[0], &arr[end]); // 最大的數(shù)跟最后一個(gè)數(shù)交換 AdjustDown(arr, end, 0); // 調(diào)堆,選出次大的數(shù) } }
三、完整代碼
(排升序要建大堆,排降序建小堆)
?? 升序:使用大堆
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> void Swap(int* pa, int* pb) { int tmp = *pa; *pa = *pb; *pb = tmp; } void AdjustDown(int arr[], int sz, int father) { int child = father * 2 + 1; while (child < sz) { if (child + 1 < sz && arr[child + 1] > arr[child]) { child += 1; } if (arr[child] > arr[father]) { Swap(&arr[child], &arr[father]); father = child; child = father * 2 + 1; } else { break; } } } /* 堆排序 - 升序 */ void HeapSort(int arr[], int sz) { /* 創(chuàng)建大堆,選出最大的數(shù) O(N) */ int father = ((sz - 1) - 1) / 2; // 計(jì)算出最后一個(gè)葉子節(jié)點(diǎn)的父親 while (father >= 0) { AdjustDown(arr, sz, father); father--; } /* 依次選數(shù),調(diào)堆 O(N * logN) */ int end = sz - 1; while (end > 0) { Swap(&arr[0], &arr[end]); // 最大的數(shù)跟最后一個(gè)數(shù)交換 AdjustDown(arr, end, 0); // 調(diào)堆,選出次大的數(shù) end--; } } void HeapPrint(int arr[], int sz) { int i = 0; for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } printf("\n"); } int main(void) { int arr[] = { 70, 56, 30, 25, 15, 10, 75, 33, 50, 69 }; int sz = sizeof(arr) / sizeof(arr[0]); printf("排序前: "); HeapPrint(arr, sz); HeapSort(arr, sz); printf("排序后: "); HeapPrint(arr, sz); return 0; }
?? 運(yùn)行結(jié)果:
? 如果要排降序呢?使用小堆即可!
?? 降序:使用小堆
#include <stdio.h> /* 交換函數(shù) */ void Swap(int* px, int* py) { int tmp = *px; *px = *py; *py = tmp; } /* 小堆下調(diào) */ void AdjustDown(int arr[], int sz, int father_idx) { int child_idx = father_idx * 2 + 1; // 計(jì)算出左孩子的值(默認(rèn)認(rèn)為左孩子大) while (child_idx < sz) { // 最壞情況:調(diào)到葉子(child >= 數(shù)組范圍時(shí)必然已經(jīng)調(diào)到葉子) if ((child_idx + 1 < sz) && (arr[child_idx + 1] < arr[child_idx])) { // 如果右孩子存在且右孩子比左孩子小 child_idx = child_idx + 1; // 讓其代表右孩子 } if (arr[child_idx] < arr[father_idx]) { // 如果孩子的值小于父親的值(不符合小堆的性質(zhì)) Swap(&arr[child_idx], &arr[father_idx]); // 交換它們的值 /* 往下走 */ father_idx = child_idx; // 更新下標(biāo) child_idx = father_idx * 2 + 1; // 計(jì)算出該節(jié)點(diǎn)路線的新父親 } else { // 如果孩子的值大于父親的值(符合小堆的性質(zhì)) break; // 終止循環(huán) } } } /* 堆排序 - 降序 */ void HeapSort(int arr[], int sz) { /* 創(chuàng)建大堆,選出最大的數(shù) O(N) */ int father = ((sz - 1) - 1) / 2; // 計(jì)算出最后一個(gè)葉子節(jié)點(diǎn)的父親 while (father >= 0) { AdjustDown(arr, sz, father); father--; } /* 依次選數(shù),調(diào)堆 O(N * logN) */ int end = sz - 1; while (end > 0) { Swap(&arr[0], &arr[end]); // 最大的數(shù)跟最后一個(gè)數(shù)交換 AdjustDown(arr, end, 0); // 調(diào)堆,選出次小的數(shù) end--; } } void PrintArray(int arr[], int sz) { for (int i = 0; i < sz; i++) { printf("%d ", arr[i]); } printf("\n"); } int main(void) { int arr[] = { 70, 56, 30, 25, 15, 10, 75, 33, 50, 69 }; int sz = sizeof(arr) / sizeof(arr[0]); printf("排序前: "); PrintArray(arr, sz); HeapSort(arr, sz); printf("排序后: "); PrintArray(arr, sz); return 0; }
?? 運(yùn)行結(jié)果:
四、證明建堆的時(shí)間復(fù)雜度
因?yàn)槎咽峭耆鏄?,而滿二叉樹也是完全二叉樹。此處為了簡(jiǎn)化,將采用滿二叉樹來證明。(時(shí)間復(fù)雜度本來看的就是近似值,所以多幾個(gè)節(jié)點(diǎn)不會(huì)影響最終結(jié)果):
假設(shè)樹的高度為:
第 層:
個(gè)節(jié)點(diǎn),需要向下移動(dòng)
層
第層:
個(gè)節(jié)點(diǎn),需要向下移動(dòng)
層
第 層:
個(gè)節(jié)點(diǎn),需要向下移動(dòng)
層
第層:
個(gè)節(jié)點(diǎn),需要向下移動(dòng)
層
……
第 層:
個(gè)節(jié)點(diǎn),需要向下移動(dòng)
層
則需要移動(dòng)節(jié)點(diǎn)總的移動(dòng)步數(shù)為:
①
②
② - ① 錯(cuò)位相減:
因此,建堆的時(shí)間復(fù)雜度為
參考資料:
Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .
百度百科[EB/OL]. []. https://baike.baidu.com/.
?? 筆者:王亦優(yōu)
?? 更新: 2021.11.26
? 勘誤: 無
?? 聲明: 由于作者水平有限,本文有錯(cuò)誤和不準(zhǔn)確之處在所難免,本人也很想知道這些錯(cuò)誤,懇望讀者批評(píng)指正!
本篇完。
到此這篇關(guān)于C語言八大排序之堆排序的文章就介紹到這了,更多相關(guān)C語言 堆排序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在Vitis?IDE中如何使用第三方庫?libtiff?保存?tiff?文件
這篇文章主要介紹了在Vitis?IDE中如何使用第三方庫?libtiff?保存?tiff?文件,本文通過圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07關(guān)于c語言逗號(hào)表達(dá)式的運(yùn)算規(guī)則知識(shí)點(diǎn)
在本篇文章里小編給大家整理的是關(guān)于c語言逗號(hào)表達(dá)式的運(yùn)算規(guī)則知識(shí)點(diǎn),需要的朋友們可以學(xué)習(xí)參考下。2020-03-03C語言實(shí)現(xiàn)自動(dòng)給QQ好友發(fā)窗口抖動(dòng)
這篇文章主要介紹了C語言實(shí)現(xiàn)自動(dòng)給QQ好友發(fā)窗口抖動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11探討:程序在內(nèi)存中的分配(常量,局部變量,全局變量,程序代碼)問題
本篇文章是對(duì)程序在的內(nèi)存中分配(常量,局部變量,全局變量,程序代碼)的問題進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05C語言深入淺出講解直接插入排序算法的實(shí)現(xiàn)
插入排序也是最簡(jiǎn)單的一類排序方法,我今天介紹的也是插入排序里最直觀且淺顯易懂的直接插入排序。對(duì)這個(gè)很簡(jiǎn)單的排序,記得當(dāng)時(shí)也是花了近兩個(gè)晚上才搞懂它的原理的,接下來就來介紹一下2022-05-05C語言實(shí)現(xiàn)abs和fabs絕對(duì)值
這篇文章主要介紹了C語言實(shí)現(xiàn)abs和fabs絕對(duì)值,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01VS+Qt+Halcon 顯示圖片,實(shí)現(xiàn)鼠標(biāo)縮放、移動(dòng)圖片
本篇博文記錄一下,用VS+Qt+Halcon實(shí)現(xiàn)對(duì)圖片的讀取以及鼠標(biāo)縮放,移動(dòng)(鼠標(biāo)事件調(diào)用了halcon自帶的算子)的過程。感興趣的可以了解一下2021-08-08C++中使用FFmpeg適配自定義編碼器的實(shí)現(xiàn)方法
本文介紹了在C++中使用FFmpeg庫進(jìn)行自定義編碼器適配的實(shí)現(xiàn)方法。文章通過具體的代碼示例,介紹了FFmpeg的基本使用方法和自定義編碼器的實(shí)現(xiàn)過程,幫助讀者了解如何在C++中進(jìn)行音視頻編碼和解碼的開發(fā)工作,并能夠?qū)崿F(xiàn)自定義的編碼器適配2023-04-04