「CS61B」Note(4) LAB10 Heap Min Priority Queue

In this lab, the task is to make a priority queue using a binary min-heap. The requirements are at this link.

leftIndex, rightIndex and parentIndex

/**
 * Returns the index of the node to the left of the node at i.
 */
private static int leftIndex(int i) {
    /* TODO: Your code here! */
    return 2 * i;
}

/**
 * Returns the index of the node to the right of the node at i.
 */
private static int rightIndex(int i) {
    /* TODO: Your code here! */
    return 2 * i + 1;
}

/**
 * Returns the index of the node that is the parent of the node at i.
 */
private static int parentIndex(int i) {
    /* TODO: Your code here! */
    return i / 2;
}

swim and sink

Loop version of swim and sink:

/**
 * Bubbles up the node currently at the given index.
 */
private void swim(int index) {
    // Throws an exception if index is invalid. DON'T CHANGE THIS LINE.
    validateSinkSwimArg(index);

    /** TODO: Your code here. */
    while (min(index, parentIndex(index)) == index && index != 1) {
        swap(index, parentIndex(index));
        index = parentIndex(index);
    }
}

/**
 * Bubbles down the node currently at the given index.
 */
private void sink(int index) {
    // Throws an exception if index is invalid. DON'T CHANGE THIS LINE.
    validateSinkSwimArg(index);

    /** TODO: Your code here. */
    while (getNode(leftIndex(index)) != null) {
        int minChildIndex = min(rightIndex(index), leftIndex(index));
        if (min(index, minChildIndex) == minChildIndex) {
            swap(index, minChildIndex);
            index = minChildIndex;
        } else break;
    }
}

Recursive version of swim and sink:

private void swim(int index) {
    // Throws an exception if index is invalid. DON'T CHANGE THIS LINE.
    validateSinkSwimArg(index);

    /** TODO: Your code here. */
    if (min(index, parentIndex(index)) == parentIndex(index) || index == 1) {
        return;
    }
    swap(index, parentIndex(index));
    swim(parentIndex(index));
}

    private void sink(int index) {
    // Throws an exception if index is invalid. DON'T CHANGE THIS LINE.
    validateSinkSwimArg(index);

    /** TODO: Your code here. */
    if (getNode(leftIndex(index)) == null) {
        return;
    }
    int minChildIndex = min(rightIndex(index), leftIndex(index));
    if (min(index, minChildIndex) == index) {
        return;
    }
    swap(index, minChildIndex);
    sink(minChildIndex);
}

insert, peek and removeMin

/**
 * Inserts an item with the given priority value. This is enqueue, or offer.
 * To implement this method, add it to the end of the ArrayList, then swim it.
 */
@Override
public void insert(T item, double priority) {
    /* If the array is totally full, resize. */
    if (size + 1 == contents.length) {
        resize(contents.length * 2);
    }

    /* TODO: Your code here! */
    size += 1;
    contents[size] = new Node(item, priority);
    swim(size);
}

/**
 * Returns the Node with the smallest priority value, but does not remove it
 * from the heap. To implement this, return the item in the 1st position of the ArrayList.
 */
@Override
public T peek() {
    /* TODO: Your code here! */
    return getNode(1).item();
}

/**
 * Returns the Node with the smallest priority value, and removes it from
 * the heap. This is dequeue, or poll. To implement this, swap the last
 * item from the heap into the root position, then sink the root. This is
 * equivalent to firing the president of the company, taking the last
 * person on the list on payroll, making them president, and then demoting
 * them repeatedly. Make sure to avoid loitering by nulling out the dead
 * item.
 */
@Override
public T removeMin() {
    /* TODO: Your code here! */
    T minItem = getNode(1).item();
    contents[1] = null;
    swap(1, size);
    sink(1);
    size -= 1;
    return minItem;
}

changePriority

/**
 * Change the node in this heap with the given item to have the given
 * priority. You can assume the heap will not have two nodes with the same
 * item. Check item equality with .equals(), not ==. This is a challenging
 * bonus problem, but shouldn't be too hard if you really understand heaps
 * and think about the algorithm before you start to code.
 */
@Override
public void changePriority(T item, double priority) {
    /* TODO: Your code here! */
    for (int i = 1; i < size + 1; i++) {
        Node node = contents[i];
        if (node.item().equals(item)) {
            if (priority > node.priority()) {
                node.myPriority = priority;
                sink(i);
            } else {
                node.myPriority = priority;
                swim(i);
            }
            return;
        }
    }
}

PQ after inserting 10 items: If change the priority of the item “b” from 2 to 6, “b” will sink down to the position of “c” and then “j”: In the end, the PQ will be like:

Test for changePriority:

@Test
public void testChangePriority() {
    ExtrinsicPQ<String> pq = new ArrayHeap<>();
    pq.insert("c", 3);
    pq.insert("i", 9);
    pq.insert("g", 7);
    pq.insert("k", 4);
    pq.insert("a", 1);
    pq.insert("h", 8);
    pq.insert("e", 5);
    pq.insert("b", 2);
    pq.insert("j", 3);
    pq.insert("d", 4);

    System.out.println("pq after inserting 10 items: ");
    System.out.println(pq);

    pq.changePriority("b", 6);

    System.out.println("pq after changing priority: ");
    System.out.println(pq);

    int i = 0;
    String[] expected = {"a", "c", "j", "d", "k", "e","b", "g", "h", "i"};
    while (pq.size() > 1) {
        assertEquals(expected[i], pq.removeMin());
        i += 1;
    }
}