Files
cAI/cKit/Foundation/c_MinHeap.c
T
2026-08-10 01:21:15 +08:00

177 lines
5.3 KiB
C

#include <c_MinHeap.h>
#include <c_Memory.h>
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
#define DEFAULT_INITIAL_CAPACITY 4
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
// 內部輔助函數:交換兩個元素的記憶體內容
C_STATIC_FORCE_INLINE
void heap_swap(char* a, char* b, int size) {
#define MAX_STACK_BUF 128
char stack_buf[MAX_STACK_BUF];
void* temp = (size <= MAX_STACK_BUF) ? stack_buf : C_ALLOC(size);
memcpy(temp, a, size);
memcpy(a, b, size);
memcpy(b, temp, size);
if (temp != stack_buf) C_FREE(temp);
}
// 內部輔助函數:向上調整,維持最小堆特性 (O(log N))
C_STATIC_FORCE_INLINE
void heapify_up(c_MinHeap_t* self, c_size_t index) {
while (index > 0) {
c_size_t parent = (index - 1) / 2;
char* curr_ptr = (char*)self->array + (index * self->obj_size);
char* parent_ptr = (char*)self->array + (parent * self->obj_size);
// 如果當前節點比父節點還小,則向上交換
if (self->compare(curr_ptr, parent_ptr) < 0) {
heap_swap(curr_ptr, parent_ptr, self->obj_size);
index = parent;
} else {
break;
}
}
}
// 內部輔助函數:向下調整,維持最小堆特性 (O(log N))
C_STATIC_FORCE_INLINE
void heapify_down(c_MinHeap_t* self, c_size_t index) {
c_size_t left, right, smallest;
char* smallest_ptr;
char* curr_ptr;
while (1) {
left = 2 * index + 1;
right = 2 * index + 2;
smallest = index;
smallest_ptr = (char*)self->array + (smallest * self->obj_size);
// 與左子節點比對優先級
if (left < self->size) {
char* left_ptr = (char*)self->array + (left * self->obj_size);
if (self->compare(left_ptr, smallest_ptr) < 0) {
smallest = left;
smallest_ptr = left_ptr;
}
}
// 與右子節點比對優先級
if (right < self->size) {
char* right_ptr = (char*)self->array + (right * self->obj_size);
if (self->compare(right_ptr, smallest_ptr) < 0) {
smallest = right;
smallest_ptr = right_ptr;
}
}
// 如果最小元素不是當前節點,交換並繼續向下遞迴
if (smallest != index) {
curr_ptr = (char*)self->array + (index * self->obj_size);
heap_swap(curr_ptr, smallest_ptr, self->obj_size);
index = smallest;
} else {
break;
}
}
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
c_err_t c_MinHeap_Init(c_MinHeap_t* self, int obj_size, c_size_t initial_capacity, c_MinHeap_Compare_f compare) {
if (!self || obj_size <= 0 || !compare) return C_ERR_PARAM;
self->obj_size = obj_size;
self->capacity = (initial_capacity > 0) ? initial_capacity : DEFAULT_INITIAL_CAPACITY;
self->size = 0;
self->compare = compare;
self->array = C_ALLOC(self->capacity * self->obj_size);
if (!self->array) {
self->capacity = 0;
return C_ERR_NOMEM;
}
return C_ERR_SUCCESS;
}
void c_MinHeap_Destroy(c_MinHeap_t* self) {
if (!self) return;
C_FREE(self->array);
self->capacity = 0;
self->size = 0;
self->obj_size = 0;
}
// 推入元素 (自動擴容)
c_err_t c_MinHeap_Push(c_MinHeap_t* self, const void* obj) {
if (!self || !self->array || !obj) return C_ERR_PARAM;
// 動態翻倍擴容邏輯
if (self->size >= self->capacity) {
const c_size_t new_capacity = self->capacity << 1;
void* new_array = C_REALLOC(self->array, new_capacity * self->obj_size);
if (!new_array) return C_ERR_NOMEM;
self->array = new_array;
self->capacity = new_capacity;
}
// 將新元素放到陣列最尾端
char* target = (char*)self->array + (self->size * self->obj_size);
memcpy(target, obj, self->obj_size);
self->size++;
// 向上修復堆平衡
heapify_up(self, self->size - 1);
return C_ERR_SUCCESS;
}
// 彈出最小元素:複製頂端資料至使用者緩衝區,並讓最尾端元素補上後向下修正
c_err_t c_MinHeap_Pop(c_MinHeap_t* self, void* out_obj) {
if (!self || !self->array || !out_obj) return C_ERR_PARAM;
if (self->size == 0) return C_ERR_EMPTY;
// 1. 複製堆頂端元素 (Index 0) 至呼叫端的自備緩衝區
memcpy(out_obj, self->array, self->obj_size);
// 2. 將最後一個元素搬移到堆頂端
if (self->size > 1) {
char* last_ptr = (char*)self->array + ((self->size - 1) * self->obj_size);
memcpy(self->array, last_ptr, self->obj_size);
}
self->size--;
// 3. 向下修復堆平衡
if (self->size > 1) {
heapify_down(self, 0);
}
return C_ERR_SUCCESS;
}
void* c_MinHeap_Peek(c_MinHeap_t* self) {
if (!self || !self->array || self->size == 0) return NULL;
return self->array; // 最小堆的頂端(最小值)永遠在陣列的第一個元素
}
c_size_t c_MinHeap_GetSize(const c_MinHeap_t* self) {
if (!self) return 0;
return self->size;
}
c_bool_t c_MinHeap_IsEmpty(const c_MinHeap_t* self) {
if (!self) return C_TRUE;
return self->size == 0;
}