diff --git a/codes/cpp/chapter_heap/my_heap.cpp b/codes/cpp/chapter_heap/my_heap.cpp index 14d450e6..56a8756a 100644 --- a/codes/cpp/chapter_heap/my_heap.cpp +++ b/codes/cpp/chapter_heap/my_heap.cpp @@ -1,7 +1,7 @@ /** * File: my_heap.cpp - * Created Time: 2023-02-03 - * Author: what-is-me (whatisme@outlook.jp) + * Created Time: 2023-02-04 + * Author: LoneRanger (836253168@qq.com), what-is-me (whatisme@outlook.jp) */ #include "../include/include.hpp" @@ -9,7 +9,7 @@ /* 最大堆类 */ class MaxHeap { private: - // 使用 vector 而非数组,这样无需考虑扩容问题 + // 使用动态数组,这样无需考虑扩容问题 vector maxHeap; /* 获取左子结点索引 */ @@ -20,50 +20,42 @@ private: /* 获取右子结点索引 */ int right(int i) { return 2 * i + 2; - } + } /* 获取父结点索引 */ int parent(int i) { - return (i - 1) / 2; // 向下整除 - } - - /* 交换元素 */ - void swap(int i, int j) { - int a = maxHeap[i], - b = maxHeap[j], - tmp = a; - maxHeap[i] = b; - maxHeap[j] = tmp; + return (i - 1) / 2; // 向下取整 } /* 从结点 i 开始,从底至顶堆化 */ - void siftUp(int i) { + void shifUp(int i) { while (true) { // 获取结点 i 的父结点 - int p = parent(i); + int p = parent(i); // 当“越过根结点”或“结点无需修复”时,结束堆化 - if (p < 0 || maxHeap[i] <= maxHeap[i]) + if (p < 0 || maxHeap[i] <= maxHeap[p]) break; // 交换两结点 - swap(i, p); + swap(maxHeap[i], maxHeap[p]); // 循环向上堆化 i = p; } } /* 从结点 i 开始,从顶至底堆化 */ - void siftDown(int i) { + void shifDown(int i) { while (true) { // 判断结点 i, l, r 中值最大的结点,记为 ma int l = left(i), r = right(i), ma = i; - if (l < size() && maxHeap[l] > maxHeap[ma]) + // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出 + if (l < size() && maxHeap[l] > maxHeap[ma]) ma = l; if (r < size() && maxHeap[r] > maxHeap[ma]) ma = r; // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出 - if (ma == i) break; - // 交换两结点 - swap(i, ma); + if (ma == i) + break; + swap(maxHeap[i], maxHeap[ma]); // 循环向下堆化 i = ma; } @@ -71,7 +63,7 @@ private: public: /* 构造函数,建立空堆 */ - MaxHeap() = default; + MaxHeap() {} /* 构造函数,根据输入列表建堆 */ MaxHeap(vector nums) { @@ -79,7 +71,7 @@ public: maxHeap = nums; // 堆化除叶结点以外的其他所有结点 for (int i = parent(size() - 1); i >= 0; i--) { - siftDown(i); + shifDown(i); } } @@ -89,13 +81,13 @@ public: } /* 判断堆是否为空 */ - bool isEmpty() { + bool empty() { return size() == 0; } /* 访问堆顶元素 */ int peek() { - return maxHeap.front(); + return maxHeap[0]; } /* 元素入堆 */ @@ -103,74 +95,77 @@ public: // 添加结点 maxHeap.push_back(val); // 从底至顶堆化 - siftUp(size() - 1); + shifUp(size() - 1); } /* 元素出堆 */ - int poll() { + void poll() { // 判空处理 - if (isEmpty()) - throw out_of_range("堆已空\n"); + if (empty()) { + cout << "Error:堆为空" << endl; + return; + } // 交换根结点与最右叶结点(即交换首元素与尾元素) - swap(0, size() - 1); + swap(maxHeap[0], maxHeap[size() - 1]); // 删除结点 - int val = maxHeap.back(); maxHeap.pop_back(); // 从顶至底堆化 - siftDown(0); - // 返回堆顶元素 - return val; + shifDown(0); } - /* 打印堆(二叉树) */ + /* 打印堆(二叉树)*/ void print() { - cout << "堆的数组表示:" << endl; - PrintUtil::printVector(this->maxHeap); + cout << "堆的数组表示:"; + PrintUtil::printVector(maxHeap); cout << "堆的树状表示:" << endl; - TreeNode *tree = vecToTree(this->maxHeap); - PrintUtil::printTree(tree); - freeMemoryTree(tree); + TreeNode *root = vecToTree(maxHeap); + PrintUtil::printTree(root); } }; -void testPush(MaxHeap &maxHeap, int val) { - maxHeap.push(val); // 元素入堆 + +void testPush(MaxHeap maxHeap, int val) { + maxHeap.push(val); cout << "\n添加元素 " << val << " 后" << endl; maxHeap.print(); } -void testPoll(MaxHeap &maxHeap) { - int val = maxHeap.poll(); // 堆顶元素出堆 - cout << "出堆元素为 " << val << endl; +void testPop(MaxHeap maxHeap) { + int val = maxHeap.peek(); + maxHeap.poll(); + cout << "\n出堆元素为 " << val << endl; maxHeap.print(); } +/* Driver Code */ int main() { /* 初始化大顶堆 */ - MaxHeap maxHeap({9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2}); + vector vec{9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2}; + MaxHeap maxheap(vec); cout << "\n输入列表并建堆后" << endl; - maxHeap.print(); + maxheap.print(); /* 获取堆顶元素 */ - int peek = maxHeap.peek(); + int peek = maxheap.peek(); cout << "\n堆顶元素为 " << peek << endl; /* 元素入堆 */ int val = 7; - maxHeap.push(val); + maxheap.push(val); cout << "\n元素 " << val << " 入堆后" << endl; - maxHeap.print(); + maxheap.print(); /* 堆顶元素出堆 */ - peek = maxHeap.poll(); + peek = maxheap.peek(); + maxheap.poll(); cout << "\n堆顶元素 " << peek << " 出堆后" << endl; - maxHeap.print(); + maxheap.print(); /* 获取堆大小 */ - int size = maxHeap.size(); + int size = maxheap.size(); cout << "\n堆元素数量为 " << size << endl; /* 判断堆是否为空 */ - bool isEmpty = maxHeap.isEmpty(); + bool isEmpty = maxheap.empty(); cout << "\n堆是否为空 " << isEmpty << endl; -} \ No newline at end of file +} diff --git a/codes/cpp/include/PrintUtil.hpp b/codes/cpp/include/PrintUtil.hpp index cd878e5a..053b9c03 100644 --- a/codes/cpp/include/PrintUtil.hpp +++ b/codes/cpp/include/PrintUtil.hpp @@ -1,7 +1,7 @@ /** * File: PrintUtil.hpp * Created Time: 2021-12-19 - * Author: Krahets (krahets@163.com), msk397 (machangxinq@gmail.com) + * Author: Krahets (krahets@163.com), msk397 (machangxinq@gmail.com), LoneRanger(836253168@qq.com) */ #pragma once diff --git a/docs/chapter_heap/heap.md b/docs/chapter_heap/heap.md index acbf6fa3..aa2ece56 100644 --- a/docs/chapter_heap/heap.md +++ b/docs/chapter_heap/heap.md @@ -29,11 +29,11 @@ comments: true
-| 方法 | 描述 | 时间复杂度 | -| --------- | -------------------------------------------- | ----------- | -| add() | 元素入堆 | $O(\log n)$ | -| poll() | 堆顶元素出堆 | $O(\log n)$ | -| peek() | 访问堆顶元素(大 / 小顶堆分别为最大 / 小值) | $O(1)$ | +| 方法 | 描述 | 时间复杂度 | +| --------- | ----------------------------------------- | ----------- | +| add() | 元素入堆 | $O(\log n)$ | +| poll() | 堆顶元素出堆 | $O(\log n)$ | +| peek() | 访问堆顶元素(大 / 小顶堆分别为最大 / 小值) | $O(1)$ | | size() | 获取堆的元素数量 | $O(1)$ | | isEmpty() | 判断堆是否为空 | $O(1)$ | @@ -287,8 +287,8 @@ comments: true === "C++" ```cpp title="my_heap.cpp" - // 使用 vector 而非数组,这样无需考虑扩容问题 - vector maxHeap; + // 使用动态数组,这样无需考虑扩容问题 + vector maxHeap; /* 获取左子结点索引 */ int left(int i) { @@ -298,11 +298,11 @@ comments: true /* 获取右子结点索引 */ int right(int i) { return 2 * i + 2; - } + } /* 获取父结点索引 */ int parent(int i) { - return (i - 1) / 2; // 向下整除 + return (i - 1) / 2; // 向下取整 } ``` @@ -418,7 +418,7 @@ comments: true ```cpp title="my_heap.cpp" /* 访问堆顶元素 */ int peek() { - return maxHeap.front(); + return maxHeap[0]; } ``` @@ -537,19 +537,19 @@ comments: true // 添加结点 maxHeap.push_back(val); // 从底至顶堆化 - siftUp(size() - 1); + shifUp(size() - 1); } - + /* 从结点 i 开始,从底至顶堆化 */ - void siftUp(int i) { + void shifUp(int i) { while (true) { // 获取结点 i 的父结点 - int p = parent(i); + int p = parent(i); // 当“越过根结点”或“结点无需修复”时,结束堆化 - if (p < 0 || maxHeap[i] <= maxHeap[i]) + if (p < 0 || maxHeap[i] <= maxHeap[p]) break; // 交换两结点 - swap(i, p); + swap(maxHeap[i], maxHeap[p]); // 循环向上堆化 i = p; } @@ -731,39 +731,39 @@ comments: true === "C++" ```cpp title="my_heap.cpp" - /* 元素出堆 */ - int poll() { - // 判空处理 - if (isEmpty()) - throw out_of_range("堆已空\n"); - // 交换根结点与最右叶结点(即交换首元素与尾元素) - swap(0, size() - 1); - // 删除结点 - int val = maxHeap.back(); - maxHeap.pop_back(); - // 从顶至底堆化 - siftDown(0); - // 返回堆顶元素 - return val; - } - /* 从结点 i 开始,从顶至底堆化 */ - void siftDown(int i) { + void shifDown(int i) { while (true) { // 判断结点 i, l, r 中值最大的结点,记为 ma int l = left(i), r = right(i), ma = i; - if (l < size() && maxHeap[l] > maxHeap[ma]) + // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出 + if (l < size() && maxHeap[l] > maxHeap[ma]) ma = l; - if (r < size() && maxHeap[r] > maxHeap[ma]) + if (r < size() && maxHeap[r] > maxHeap[ma]) ma = r; // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出 - if (ma == i) break; - // 交换两结点 - swap(i, ma); + if (ma == i) + break; + swap(maxHeap[i], maxHeap[ma]); // 循环向下堆化 i = ma; } } + + /* 元素出堆 */ + void poll() { + // 判空处理 + if (empty()) { + cout << "Error:堆为空" << endl; + return; + } + // 交换根结点与最右叶结点(即交换首元素与尾元素) + swap(maxHeap[0], maxHeap[size() - 1]); + // 删除结点 + maxHeap.pop_back(); + // 从顶至底堆化 + shifDown(0); + } ``` === "Python" @@ -921,10 +921,9 @@ comments: true maxHeap = nums; // 堆化除叶结点以外的其他所有结点 for (int i = parent(size() - 1); i >= 0; i--) { - siftDown(i); + shifDown(i); } } - // Tip: std::make_heap() 函数可以原地建堆。 ``` === "Python"