diff --git a/codes/c/CMakeLists.txt b/codes/c/CMakeLists.txt index 1a208dd9d..3b239e7e6 100644 --- a/codes/c/CMakeLists.txt +++ b/codes/c/CMakeLists.txt @@ -10,3 +10,4 @@ add_subdirectory(chapter_computational_complexity) add_subdirectory(chapter_array_and_linkedlist) add_subdirectory(chapter_sorting) add_subdirectory(chapter_tree) +add_subdirectory(chapter_heap) diff --git a/codes/c/chapter_heap/CMakeLists.txt b/codes/c/chapter_heap/CMakeLists.txt new file mode 100644 index 000000000..c94ec9c16 --- /dev/null +++ b/codes/c/chapter_heap/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(my_heap my_heap.c) + diff --git a/codes/c/chapter_heap/my_heap.c b/codes/c/chapter_heap/my_heap.c new file mode 100644 index 000000000..43f4dc272 --- /dev/null +++ b/codes/c/chapter_heap/my_heap.c @@ -0,0 +1,185 @@ +/** + * File: my_heap.c + * Created Time: 2023-01-15 + * Author: Reanon (793584285@qq.com) + */ + +#include "../include/include.h" + +#define MAX_SIZE 5000 + +// 大顶堆 +typedef struct maxHeap { + // size 代表的是实际元素的个数 + int size; + // 使用预先分配内存的数组,避免扩容 + int data[MAX_SIZE]; +} maxHeap; + +void siftDown(maxHeap *h, int i); + +void siftUp(maxHeap *h, int i); + +/* 构造空堆 */ +maxHeap *newEmptyMaxHeap() { + // 所有元素入堆 + maxHeap *h = (maxHeap *) malloc(sizeof(maxHeap)); + h->size = 0; + return h; +} + +/* 构造函数,根据切片建堆 */ +maxHeap *newMaxHeap(int nums[], int size) { + // 所有元素入堆 + maxHeap *h = (maxHeap *) malloc(sizeof(maxHeap)); + h->size = size; + memcpy(h->data, nums, size * sizeof(int)); + for (int i = size - 1; i >= 0; i--) { + // 堆化除叶结点以外的其他所有结点 + siftDown(h, i); + } + return h; +} + +/* 获取左子结点索引 */ +int left(maxHeap *h, int i) { + return 2 * i + 1; +} + +/* 获取右子结点索引 */ +int right(maxHeap *h, int i) { + return 2 * i + 2; +} + +/* 获取父结点索引 */ +int parent(maxHeap *h, int i) { + return (i - 1) / 2; +} + +/* 交换元素 */ +int swap(maxHeap *h, int i, int j) { + int temp = h->data[i]; + h->data[i] = h->data[j]; + h->data[j] = temp; +} + +/* 获取堆大小 */ +int size(maxHeap *h) { + return h->size; +} + +/* 判断堆是否为空 */ +int isEmpty(maxHeap *h) { + return h->size == 0; +} + +/* 访问堆顶元素 */ +int peek(maxHeap *h) { + return h->data[0]; +} + +/* 元素入堆 */ +int push(maxHeap *h, int val) { + // 默认情况下,不应该添加这么多结点 + if (h->size == MAX_SIZE) { + printf("heap is full!"); + return NIL; + } + // 添加结点 + h->data[h->size] = val; + h->size++; + + // 从底至顶堆化 + siftUp(h, h->size - 1); +} + +/* 元素出堆 */ +int poll(maxHeap *h) { + // 判空处理 + if (isEmpty(h)) { + printf("heap is empty!"); + return NIL; + } + // 交换根结点与最右叶结点(即交换首元素与尾元素) + swap(h, 0, size(h) - 1); + // 删除结点 + int val = h->data[h->size - 1]; + h->size--; + // 从顶至底堆化 + siftDown(h, 0); + + // 返回堆顶元素 + return val; +} + + +/* 从结点 i 开始,从顶至底堆化 */ +void siftDown(maxHeap *h, int i) { + while (true) { + // 判断结点 i, l, r 中值最大的结点,记为 max + int l = left(h, i); + int r = right(h, i); + int max = i; + if (l < size(h) && h->data[l] > h->data[max]) { + max = l; + } + if (r < size(h) && h->data[r] > h->data[max]) { + max = r; + } + // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出 + if (max == i) { + break; + } + // 交换两结点 + swap(h, i, max); + // 循环向下堆化 + i = max; + } +} + +/* 从结点 i 开始,从底至顶堆化 */ +void siftUp(maxHeap *h, int i) { + while (true) { + // 获取结点 i 的父结点 + int p = parent(h, i); + // 当“越过根结点”或“结点无需修复”时,结束堆化 + if (p < 0 || h->data[i] <= h->data[p]) { + break; + } + // 交换两结点 + swap(h, i, p); + // 循环向上堆化 + i = p; + } +} + +int main() { + /* 初始化堆 */ + // 初始化大顶堆 + int nums[] = {9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2}; + maxHeap *heap = newMaxHeap(nums, sizeof(nums) / sizeof(int)); + printf("输入数组并建堆后\n"); + printHeap(heap->data, heap->size); + + /* 获取堆顶元素 */ + printf("\n堆顶元素为 %d\n", peek(heap)); + + /* 元素入堆 */ + push(heap, 7); + printf("\n元素 7 入堆后\n"); + printHeap(heap->data, heap->size); + + /* 堆顶元素出堆 */ + int top = poll(heap); + printf("\n堆顶元素 %d 出堆后\n", top); + printHeap(heap->data, heap->size); + + /* 获取堆大小 */ + printf("\n堆元素数量为 %d\n", size(heap)); + + /* 判断堆是否为空 */ + printf("\n堆是否为空 %d\n", isEmpty(heap)); + + // 释放内存 + free(heap); +} \ No newline at end of file diff --git a/codes/c/include/print_util.h b/codes/c/include/print_util.h index a0c3a1500..0328a73d6 100644 --- a/codes/c/include/print_util.h +++ b/codes/c/include/print_util.h @@ -25,7 +25,7 @@ extern "C" { * @param arr * @param size */ -static void printArray(int *arr, int size) { +static void printArray(int arr[], int size) { printf("["); for (int i = 0; i < size - 1; i++) { if (arr[i] != NIL) { @@ -36,7 +36,7 @@ static void printArray(int *arr, int size) { } if (arr[size - 1] != NIL) { printf("%d]\n", arr[size - 1]); - }else{ + } else { printf("NULL]\n"); } } @@ -127,6 +127,21 @@ static void printTree(TreeNode *root) { printTreeHelper(root, NULL, false); } +/** + * @brief Print a Heap + * + * @param arr + * @param size + */ +static void printHeap(int arr[], int size) { + TreeNode * root; + printf("堆的数组表示:"); + printArray(arr, size); + printf("堆的树状表示:\n"); + root = arrToTree(arr, size); + printTree(root); +} + #ifdef __cplusplus }