本文基於 C 語言實現一個通用的**優先隊列**,底層數據結構採用**二叉堆**,並深度解析 C/C++ 中 const 關鍵字在變量、指針、函數參數、返回值、類成員中的多維用法與陷阱。
// 鍵值對節點
typedef struct KeyValue {
int key; // 優先級鍵
void *value; // 業務數據指針
} KeyValue;
// 優先隊列結構體
typedef struct PriorityQueue {
KeyValue **nodes; // 二叉堆數組 (指針數組)
int size; // 當前元素數量
int capacity; // 數組容量
int priority; // PRIORITY_MAX(1) 或 PRIORITY_MIN(2)
} PriorityQueue;
| 函數 | 功能 | 時間複雜度 |
|---|---|---|
priority_queue_new(priority) | 創建隊列,指定大/小頂堆 | O(1) |
priority_queue_enqueue(pq, kv) | 入隊 (上浮調整) | O(log n) |
priority_queue_dequeue(pq) | 出隊取頂 (下沉調整) | O(log n) |
priority_queue_top(pq) | 查看隊首 (不刪除) | O(1) |
priority_queue_size/empty(pq) | 狀態查詢 | O(1) |
priority_queue_free(pq, freeValue) | 銷毀隊列,回調釋放 value 內存 | O(n) |
nodes[size],size++,當前索引 i = size-1,父節點 parent = (i-1)/2。若當前優先級高於父節點,交換並 i = parent 繼續,直到根或不大於父節點。nodes[0] 為返回值,將尾節點 nodes[size-1] 移至根,size--。從根開始,比較左右子節點 left=2*i+1, right=2*i+2,找出優先級最高的子節點 j,若根優先級低於 j,交換並 i=j 繼續,直到葉子或不低於子節點。static void priority_queue_realloc(PriorityQueue *pq) {
pq->capacity *= 2;
pq->nodes = realloc(pq->nodes, sizeof(KeyValue*) * pq->capacity);
}
const 核心語義:**「只讀」**,編譯器強制檢查,運行期無開銷,助於優化與防錯。
口訣:從右向左讀,遇 * 說「指向」,遇 const 說「只讀」。
| 聲明 | 含義 | 可修改項 |
|---|---|---|
const int *p / int const *p | 指向 常量整數的指針 | 指針 p 本身 |
int * const p | 指向整數的 常量指針 | 指向的值 *p |
const int * const p | 指向常量整數的 常量指針 | 無 |
void func(const int n):傳值參數無意義 (副本本身可改)。void func(const char *str):承諾不修改字符串內容,可接收字符串字面量。void func(char * const ptr):承諾不修改指針本身 (少用)。void func(const MyClass &obj):引用傳參避免拷貝,且保護對象不被修改 (C++ 核心用法)。const int func():返回值為常量 (內置類型無實際意義)。const char* func():返回指向常量的指針,調用者不可修改內容。char* const func():返回常量指針 (極少見)。| 場景 | 語法 | 效果 |
|---|---|---|
| 常量成員變量 | const int MAX_SIZE; | 初始化列表賦值,對象生命周期內不可改 |
| 常量成員函數 | void print() const; | 承諾不修改非 mutable 成員,可被 const 對象調用 |
| const 對象 | const MyClass obj; | 只能調用 const 成員函數 |
| 維度 | const | #define |
|---|---|---|
| 階段 | 編譯/運行期 | 預處理期 (文本替換) |
| 類型安全 | 有類型檢查 | 無類型,純文本 |
| 作用域 | 遵循作用域規則 | 全局文件級 |
| 內存 | 分配內存 (可取址) | 不分配,純展開 |
| 調試 | 符號表可見 | 符號表不可見 |
void func(int **p) 不能傳 const int ** (雙重指針 const 轉換規則嚴格)。const_cast 移除 const (危險,僅用於對接舊 API)。代碼採用**基於對象**風格:結構體封裝數據,函數指針作為方法,構造/析構函數管理生命周期,私有函數靜態內聯。編譯命令:gcc pq.c main.c -o pq_test。
二叉堆優先隊列是經典數據結構,C 語言手動管理內存配合 const 防禦性編程,能構建高效、健壯的系統級組件。掌握 const 的「右左讀法」與各層級語義,是 C/C++ 進階的必修課。