chapter_heap/heap/ #242
Replies: 69 comments 79 replies
-
这部分的py我先预定一下。今晚回去更一下 |
Beta Was this translation helpful? Give feedback.
-
"输入数据并建堆"小节中提到“元素入堆的时间复杂度为O(n)”,这里应该是O(logn)吧,“元素入堆”那一小节也提到了这一点(ps.很感谢k神的教程,一路看下来帮助很大(刚刚回复到别人的评论上了不好意思orz |
Beta Was this translation helpful? Give feedback.
-
歪个楼,想请问下堆顶元素出堆的poll()用的是单词的哪个含义呀,有无英语好的大佬解答一下呢。是poll的头顶,顶部;还是轮询,查询 |
Beta Was this translation helpful? Give feedback.
-
heap.java 堆顶元素出堆好像没有名为heap的堆 |
Beta Was this translation helpful? Give feedback.
-
请问一下,堆排序怎么样的,能不能补充一下呢。二叉搜索树排序能明白,但是堆 “依次将所有元素弹出”也不是有序的啊,只是上面的比下面的大,下面的还是保证不了顺序的。能简单说一下吗?谢谢大佬 |
Beta Was this translation helpful? Give feedback.
-
k神,堆初始化的时候,这一段代码没搞明白, |
Beta Was this translation helpful? Give feedback.
-
k神,代码里的注释能不能写的更详细一点,特别是这几节我每次看代码都要理解好久,// 当“越过根节点”或“节点无需修复”时,结束堆化if (p < 0 || maxHeap.get(i) <= maxHeap.get(p)),就像这里p<0,我想了好一会才理解它是根据parent()表示的越过根节点。 |
Beta Was this translation helpful? Give feedback.
-
siftUp(size() - 1); k神,这里的 |
Beta Was this translation helpful? Give feedback.
-
不错,感觉可以和cookbook一起看,labuladong的感觉不适合算法新手完全看不进去 |
Beta Was this translation helpful? Give feedback.
-
堆顶元素出堆 为什么选择操作交换堆顶和最右子节点而不是交换堆顶和最底层最左子节点呢? |
Beta Was this translation helpful? Give feedback.
-
为何没有PHP? |
Beta Was this translation helpful? Give feedback.
-
my_heap.cpp多了行注释// 若节点 i 最大或索引 l, r 越界,则无须继续堆化,跳出 |
Beta Was this translation helpful? Give feedback.
-
不错,跟《Java编程的逻辑》一起看,看看Java的实现,看看大佬的实现,加强印象 |
Beta Was this translation helpful? Give feedback.
-
元素入堆那里,高度为什么要加上时间复杂度啊 |
Beta Was this translation helpful? Give feedback.
-
您这回复效率,实在令人佩服…… |
Beta Was this translation helpful? Give feedback.
-
請問 C 的索引映射公式函數是不是多了 |
Beta Was this translation helpful? Give feedback.
-
搞了个动态可视化来解释堆的操作,可以看 https://gallery.selfboot.cn/algorithms/heap/ |
Beta Was this translation helpful? Give feedback.
-
k神,我想问一下你这个动画图片是怎么生成的,用的什么软件吗?我在想一种可能,如果各种排序,各种递归之类的都有相应的动画图解,那理解起来就简单多了,也不需要自己手动画图,所以k神,这是啥软件或者什么技术手段,我也想研究一下,便于我理解别的知识点,免去手动画图的步骤.谢谢! |
Beta Was this translation helpful? Give feedback.
-
堆默认是最常使用的二叉堆,而二叉堆只是优先队列的一种是实现方式 |
Beta Was this translation helpful? Give feedback.
-
NOTE:用 |
Beta Was this translation helpful? Give feedback.
-
想了一下,其实这里提供的方法也完全能删除任意一个节点对吧?也是把要删除的节点和堆底元素(最右叶节点)交换后删除,然后从这个换过来的节点开始进行堆化。甚至代码都不用改,只要更改传进去的swap和siftdown函数的节点索引就行。(我知道删除根节点的带来的意义重大,删除任意节点没什么意义,就是单纯思考了一下这个问题) |
Beta Was this translation helpful? Give feedback.
-
作者你好,堆的初始化结构没写,我根据后面的结构,补充了一下C语言版本的MaxHeap的结构 |
Beta Was this translation helpful? Give feedback.
-
if (p < 0 || maxHeap.get(i) <= maxHeap.get(p)) |
Beta Was this translation helpful? Give feedback.
-
我将最小堆的实现封装为了一个类 using namespace std; class MinHeap { }; bool MinHeap::isEmpty() { int MinHeap::right(int i) { int MinHeap::parent(int i) { int MinHeap::peek() { int MinHeap::size() { void MinHeap::push(int i) { } void MinHeap::pop() {
} void MinHeap::printMinHeap() { int main() {
} |
Beta Was this translation helpful? Give feedback.
-
小顶堆的实现,只需要修改Heaptify的向上和向下过程即可。 // 小顶堆: 对 heaptifyUp 和 heaptifyDown 函数的逻辑进行一些调整。
void initHeap(float **arr, int *size) { *arr = (float *)malloc(sizeof(float) * MAX_SIZE); *size = 0; }
void peekTop(float *arr, int size, float *x) { if (size <= 0) return; *x = arr[0]; }
void getParent(int i, int *p_idx) { *p_idx = (i - 1) / 2; }
void getLeftChild(int i, int *lc_idx) { *lc_idx = 2 * i + 1; }
void getRightChild(int i, int *rc_idx) { *rc_idx = 2 * i + 2; }
void heaptifyUp(float *arr, int idx) { // 比较当前节点与其父节点的大小。如果当前节点的值小于父节点的值,则交换它们,并继续向上调整。
int cur = idx;
while (cur > 0) { // 只要 cur 不是根节点
int par; getParent(cur, &par); if (arr[cur] >= arr[par]) break; // 如果当前节点大于等于父节点,退出循环
float tmp = arr[cur]; arr[cur] = arr[par]; arr[par] = tmp; cur = par; // 交换当前节点和父节点, 更新 cur 为父节点索引
}
}
void heaptifyDown(float *arr, int size, int idx) { // 比较当前节点与其左右子节点的大小。选择最小的子节点,如果当前节点大于这个子节点,则交换它们,并继续向下调整。
int cur = idx;
while (true) {
int lc, rc, minidx = cur; getLeftChild(cur, &lc); getRightChild(cur, &rc);
if (lc < size && arr[lc] < arr[minidx]) { minidx = lc; } // 找到当前节点和左子节点中的最小值
if (rc < size && arr[rc] < arr[minidx]) { minidx = rc; } // 找到当前节点和右子节点中的最小值
if (minidx == cur) break; // 如果当前节点是最小值,退出循环
float tmp = arr[cur]; arr[cur] = arr[minidx]; arr[minidx] = tmp; cur = minidx; // 交换当前节点和最小值节点, 更新 cur 为新的索引
}
}
void pushHeap(float *arr, int *size, float x) {
if ((*size) >= MAX_SIZE) return; // 如果堆已满,直接返回
arr[*size] = x; (*size)++; // 将新元素放在堆的最后一个位置
heaptifyUp(arr, (*size) - 1); // 重新调整堆
}
void popHeap(float *arr, int *size, float *val) {
if ((*size) <= 0) return; // 如果堆为空,直接返回
*val = arr[0]; arr[0] = arr[(*size) - 1]; // 将堆的最后一个元素放在堆顶
(*size)--; heaptifyDown(arr, *size, 0); // 重新调整堆
}
void freeHeap(float **arr) { if (*arr) { free(*arr); *arr = NULL; } } |
Beta Was this translation helpful? Give feedback.
-
parent函数通常实现为(i - 1) // 2,因为在数组表示的堆中,节点i的父节点索引是(i - 1) // 2。这里我想了一会儿才想起来 |
Beta Was this translation helpful? Give feedback.
-
Python 小提示:
from collections import deque
import heapq |
Beta Was this translation helpful? Give feedback.
-
C void swap(int* a, int* b) {
*a ^= *b; // a ^ b
*b ^= *a; // a ^ b ^ b = a
*a ^= *b; // a ^ b ^ a = b
} |
Beta Was this translation helpful? Give feedback.
-
Queue maxHeap = new PriorityQueue<>((a, b) -> b - a); |
Beta Was this translation helpful? Give feedback.
-
请教一下大家元素入堆操作的C++代码部分: /* 元素入堆 */
void push(int val) {
// 添加节点
maxHeap.push_back(val);
// 从底至顶堆化
siftUp(size() - 1);
}
/* 从节点 i 开始,从底至顶堆化 */
void siftUp(int i) {
while (true) {
// 获取节点 i 的父节点
int p = parent(i);
// 当“越过根节点”或“节点无须修复”时,结束堆化
if (p < 0 || maxHeap[i] <= maxHeap[p])
break;
// 交换两节点
swap(maxHeap[i], maxHeap[p]);
// 循环向上堆化
i = p;
}
} 为什么可以直接使用 看了一下github仓库clone下来的代码,是定义了一个size函数return maxHeap.size() /* 获取堆大小 */
int size() {
return maxHeap.size();
} 感觉还是容易造成一点混淆的,因为有的读者可能会像我一样主要看网站和书,偶尔去看看完整的代码 |
Beta Was this translation helpful? Give feedback.
-
chapter_heap/heap/
一本动画图解、能运行、可提问的数据结构与算法入门书
https://www.hello-algo.com/chapter_heap/heap/
Beta Was this translation helpful? Give feedback.
All reactions