我的 C++ 堆实现有什么问题?
What is wrong with my C++ heap implementation?
我正在尝试为在线法官实现一个堆结构。实现很满意,我所有的测试用例都通过了,但是在线评委拒绝了。
insert 函数追加新元素,然后将其冒泡到二叉树中。 removeMax 函数用向量中的最后一个元素替换最大的元素,然后将其冒泡。
vector<int> heap;
int getMax(){
return heap[0];
}
int getSize(){
return heap.size();
}
void insert(int element){
heap.push_back(element);
int i = heap.size() - 1;
while(element > heap[i / 2]) {
swap(heap[i], heap[i / 2]);
i = i / 2;
}
}
void removeMax(){
heap[0] = heap[heap.size() - 1];
heap.pop_back();
int i = 0;
int iGreater = heap[i * 2] > heap[i * 2 + 1] ? i * 2 : i * 2 + 1;
while(i < heap.size() && heap[i] < heap[iGreater]) {
swap(heap[i], heap[iGreater]);
i = iGreater;
iGreater = heap[i * 2] > heap[i * 2 + 1] ? i * 2 : i * 2 + 1;
}
}
您正在使用堆方程式:
- 节点 i 的父节点是节点 i/2
- 节点 i 的子节点是节点 2*i 和 2*i + 1
仅当您使用基于 1 的数组索引时才有效(索引 1 是数组的第一个元素)
但是 C++ 对向量(和数组)使用基于 0 的索引,所以这不起作用。你需要
- 节点 i 的父节点是节点 (i-1)/2
- 节点 i 的子节点是节点 2*i + 1 和 2*i + 2
你的 removeMax 结束条件也是错误的,导致你 运行 离开向量的末尾并得到未定义的行为。
几个问题:
在zero-indexed 向量中,索引i
处节点的children 位于i * 2 + 1
和i * 2 + 2
。索引 i
处节点的 parent 位于 (i - 1) / 2
insert
函数中的while
循环到达根节点时必须退出,因为根没有parent。所以 i > 0
也应该是一个循环条件。
removeMax
应首先确保堆不为空,否则 heap[heap.size() - 1]
将有未定义的行为。
在赋值给iGreater
之前首先要确保当前节点有children,否则像heap[i * 2 + 1]
这样的表达式会有未定义的行为。也应该预见到一个节点只有一个 child 的情况。
这里更正:
void insert(int element){
heap.push_back(element);
int i = heap.size() - 1;
while (i > 0 && element > heap[(i - 1) / 2]) {
swap(heap[i], heap[(i - 1) / 2]);
i = (i - 1) / 2;
}
}
void removeMax(){
if (heap.size() == 0) {
return;
}
heap[0] = heap[heap.size() - 1];
heap.pop_back();
int i = 0;
while (i * 2 + 1 < heap.size()) {
int iGreater = i * 2 + 1;
if (iGreater + 1 < heap.size() && heap[iGreater + 1] > heap[iGreater]) {
iGreater++;
}
if (heap[i] >= heap[iGreater]) {
break;
}
swap(heap[i], heap[iGreater]);
i = iGreater;
}
}
我正在尝试为在线法官实现一个堆结构。实现很满意,我所有的测试用例都通过了,但是在线评委拒绝了。
insert 函数追加新元素,然后将其冒泡到二叉树中。 removeMax 函数用向量中的最后一个元素替换最大的元素,然后将其冒泡。
vector<int> heap;
int getMax(){
return heap[0];
}
int getSize(){
return heap.size();
}
void insert(int element){
heap.push_back(element);
int i = heap.size() - 1;
while(element > heap[i / 2]) {
swap(heap[i], heap[i / 2]);
i = i / 2;
}
}
void removeMax(){
heap[0] = heap[heap.size() - 1];
heap.pop_back();
int i = 0;
int iGreater = heap[i * 2] > heap[i * 2 + 1] ? i * 2 : i * 2 + 1;
while(i < heap.size() && heap[i] < heap[iGreater]) {
swap(heap[i], heap[iGreater]);
i = iGreater;
iGreater = heap[i * 2] > heap[i * 2 + 1] ? i * 2 : i * 2 + 1;
}
}
您正在使用堆方程式:
- 节点 i 的父节点是节点 i/2
- 节点 i 的子节点是节点 2*i 和 2*i + 1
仅当您使用基于 1 的数组索引时才有效(索引 1 是数组的第一个元素)
但是 C++ 对向量(和数组)使用基于 0 的索引,所以这不起作用。你需要
- 节点 i 的父节点是节点 (i-1)/2
- 节点 i 的子节点是节点 2*i + 1 和 2*i + 2
你的 removeMax 结束条件也是错误的,导致你 运行 离开向量的末尾并得到未定义的行为。
几个问题:
在zero-indexed 向量中,索引
i
处节点的children 位于i * 2 + 1
和i * 2 + 2
。索引i
处节点的 parent 位于(i - 1) / 2
insert
函数中的while
循环到达根节点时必须退出,因为根没有parent。所以i > 0
也应该是一个循环条件。removeMax
应首先确保堆不为空,否则heap[heap.size() - 1]
将有未定义的行为。在赋值给
iGreater
之前首先要确保当前节点有children,否则像heap[i * 2 + 1]
这样的表达式会有未定义的行为。也应该预见到一个节点只有一个 child 的情况。
这里更正:
void insert(int element){
heap.push_back(element);
int i = heap.size() - 1;
while (i > 0 && element > heap[(i - 1) / 2]) {
swap(heap[i], heap[(i - 1) / 2]);
i = (i - 1) / 2;
}
}
void removeMax(){
if (heap.size() == 0) {
return;
}
heap[0] = heap[heap.size() - 1];
heap.pop_back();
int i = 0;
while (i * 2 + 1 < heap.size()) {
int iGreater = i * 2 + 1;
if (iGreater + 1 < heap.size() && heap[iGreater + 1] > heap[iGreater]) {
iGreater++;
}
if (heap[i] >= heap[iGreater]) {
break;
}
swap(heap[i], heap[iGreater]);
i = iGreater;
}
}