-1

I'm trying to print the last level in a min heap. I thought I had code that works, but one of the test cases fail. In terms of the test cases, I only have access to how the output does not match.

Here is my code:

#include "MinHeap.h"
#include <math.h>

using std::log2;

vector<int> lastLevel(MinHeap & heap)
{
        // Your code here
        vector<int> leaves;
        int capacity = pow(2, log2(heap.elements.size()) + 1) - 1;
        for (unsigned leaf = capacity / 2; leaf < heap.elements.size(); leaf++) {
                leaves.push_back(heap.elements[leaf]);
        }
        return leaves;
}

And here is the MinHeap class that goes along with it:

#include "MinHeap.h"

MinHeap::MinHeap(const vector<int> & vector)
{
    int inf = numeric_limits<int>::min();
    elements.push_back(inf);
    elements.insert(elements.end(), vector.begin(), vector.end());
    buildHeap();
}

MinHeap::MinHeap()
{
    int inf = numeric_limits<int>::min();
    elements.push_back(inf);
}

void MinHeap::buildHeap()
{
    std::sort(elements.begin() + 1, elements.end());
}

void MinHeap::heapifyDown(int index)
{
    int length = elements.size();
    int leftChildIndex = 2 * index;
    int rightChildIndex = 2 * index + 1;

    if (leftChildIndex >= length)
        return; // index is a leaf

    int minIndex = index;

    if (elements[index] > elements[leftChildIndex]) {
        minIndex = leftChildIndex;
    }

    if ((rightChildIndex < length)
        && (elements[minIndex] > elements[rightChildIndex])) {
        minIndex = rightChildIndex;
    }

    if (minIndex != index) {
        // need to swap
        int temp = elements[index];
        elements[index] = elements[minIndex];
        elements[minIndex] = temp;
        heapifyDown(minIndex);
    }
}

void MinHeap::heapifyUp(int index)
{
    if (index < 2)
        return;

    int parentIndex = index / 2;

    if (elements[parentIndex] > elements[index]) {
        int temp = elements[parentIndex];
        elements[parentIndex] = elements[index];
        elements[index] = temp;
        heapifyUp(parentIndex);
    }
}

void MinHeap::insert(int newValue)
{
    int length = elements.size();
    elements.push_back(newValue);
    heapifyUp(length);
}

int MinHeap::peek() const
{
    return elements.at(1);
}

int MinHeap::pop()
{
    int length = elements.size();
    int p = -1;

    if (length > 1) {
        p = elements[1];
        elements[1] = elements[length - 1];
        elements.pop_back();
        heapifyDown(1);
    }

    return p;
}

void MinHeap::print() const
{
    if (elements.size() > 1) {
        int length = elements.size();
        cout << "[";
        for (int i = 1; i < length - 1; i++) {
            cout << elements[i] << ", ";
        }
        cout << elements[elements.size() - 1] << "]" << endl;
    } else {
        cout << "[ ]" << endl;
    }
}

Here is the output I get showing one of the test cases fail:

tests.cpp:31: FAILED:
  REQUIRE( s_lastLevel(h) == lastLevel(h) )
with expansion:
  { 1804289383 (0x6b8b4567), 1681692777 (0x643c9869) }
  ==
  { 1681692777 (0x643c9869) }

===============================================================================
test cases: 1 | 1 failed
assertions: 3 | 2 passed | 1 failed

I'm not sure why my initial approach is failing. Much help is appreciated.

HughJass24
  • 39
  • 1
  • 4

1 Answers1

1

It seems like the problem is in this line:

int capacity = pow(2, log2(heap.elements.size()) + 1) - 1;

What you are doing here is equivalent to:

int capacity = 2 * heap.elements.size() - 1;

What you instead want to do is get the index of the parent of the last element and increment by one as the starting position of your iteration. Since children of a node at i are at 2i and 2i+1, you can simply divide the index of the last node (n-1) by two and add one. You can check that this must be a leaf since its children would be at 2 * ((n-1)/2 + 1) and 2 * ((n-1)/2 + 1) + 1 which are both guaranteed equal or grater than n. So this will return all leaves:

int start = (heap.elements.size() - 1) / 2 + 1;
for (unsigned leaf = start; leaf < heap.elements.size(); leaf++) {
    leaves.push_back(heap.elements[leaf]);
}
return leaves;

If it is just the last level you want, start at the largest power of two smaller than the index of the last element (n-1):

int start = 1 << (int)(log2(heap.elements.size()-1));
for (unsigned leaf = start; leaf < heap.elements.size(); leaf++) {
    leaves.push_back(heap.elements[leaf]);
}
return leaves;
  • What is the ```1 << (int)(log2(heap.elements.size()-1))``` line supposed to do exactly? I don't think I've seen the output operator used in that way before. – HughJass24 Apr 07 '21 at 03:00
  • That is not an output operator, it a left bitshift operator. `a << x` shifts the bitwise representation of `a` `x` steps to the left (see [this](https://www.geeksforgeeks.org/left-shift-right-shift-operators-c-cpp/) for example). Note that `a << x` is the same as `a * std::pow(2, x)` sinse shifting bits left is equivalent to multiplying by 2. Since it is a bitwise operation on an integer, it is a computationally cheaper operation than floating point arithmetic (like `std::pow`). – Gilles Ottervanger Apr 07 '21 at 14:28