I've been trying to write a recursive method that reshapes a heap data structure when an element is enqueued, but I cannot get it to work correctly.
I was able to get a perfectly working recursive reheapDown method, so I have no idea why this one won't work. Here is the class I've been working on, which includes the iterative version of reheapUp which I'm using as a template for designing the recursive version:
public class Heap<T extends Comparable<T>> implements PriQueueInterface<T>
{
private ArrayList<T> elements; // priority queue elements
private int lastIndex; // index of last element in priority queue
private int maxIndex; // index of last position in ArrayList
public Heap(int maxSize)
{
elements = new ArrayList<T>(maxSize);
lastIndex = -1;
maxIndex = maxSize - 1;
}
public boolean isEmpty()
// Returns true if this priority queue is empty; otherwise, returns false.
{
return (lastIndex == -1);
}
public boolean isFull()
// Returns true if this priority queue is full; otherwise, returns false.
{
return (lastIndex == maxIndex);
}
private void reheapUp(T element)
// Current lastIndex position is empty.
// Inserts element into the tree and ensures shape and order properties.
{
int hole = lastIndex;
while ((hole > 0) // hole is not root and element > hole's parent
&&
(element.compareTo(elements.get((hole - 1) / 2)) > 0))
{
// move hole's parent down and then move hole up
elements.set(hole,elements.get((hole - 1) / 2));
hole = (hole - 1) / 2;
}
elements.set(hole, element); // place element into final hole
}
private void recReheapUp(T element)
{
int hole = lastIndex;
//hole is not root and element > hole's parent
if (hole > 0)
{
if (element.compareTo(elements.get((hole - 1) / 2)) > 0)
{
elements.set(hole,elements.get((hole - 1) / 2));
hole = (hole - 1) / 2;
}
}
//base condition
if (hole == 0 && element.compareTo(elements.get((hole - 1) / 2)) <= 0))
{
elements.set(hole, element); // place element into final hole
return;
}
recReheapUp(element);
}
public void enqueue(T element) throws PriQOverflowException
// Throws PriQOverflowException if this priority queue is full;
// otherwise, adds element to this priority queue.
{
if (lastIndex == maxIndex)
throw new PriQOverflowException("Priority queue is full");
else
{
lastIndex++;
elements.add(lastIndex,element);
recReheapUp(element);
}
}
The reheapUp() and recReheapUp() methods are called whenever an item is enqueued into the heap. I've reworked the recReheapUp() method so many times it's not even worth posting all the changes I've attempted.
I will say that I think the issue lies in my base case, although there may be logical flaws in the general case as well.
I keep getting stack overflow errors no matter what I do, which tells me the recursive method isn't terminating properly. I just recently switched to nested if statements for my recursive method, but I'm not sure if that helped or hurt my cause.
Looks like you're getting stuck in unbounded recursive calls not because there's anything wrong with your base case (although I'm not sure I understand what the inner comparison is for), but because you're effectively calling Heapify on the same element. Your recursive algorithm should know the index of the current element that may need to sift. Something like this:
private void insert(ArrayList<T> heap, T element) {
head.add(element);
heapify(heap, heap.size() - 1);
}
private void heapify(ArrayList<T> heap, int location) {
int parent = (location - 1) / 2; // -1 for zero-indexed language
// same-element comparison is OK. This will always happen at the root.
if (heap.get(parent).compareTo(heap.get(location)) > 0) {
swap(heap, location, parent);
heapify(heap, parent);
}
}
private void swap(ArrayList<T> heap, int a, int b) {
T temp = heap.get(a);
heap.set(a, heap.get(b));
heap.set(b, temp);
}
CLRS has a really excellent discussion on Heaps on pages 151-159.
Related
I am preparing for a data structures and algorithms final exam. I am trying to work through all of the data structures we have learnt this semester and program them by my self to help prepare me for the final. I am working on the max heap right now which includes a inserting (with a heapify) and a retrieve max. I am stuck on the heapifying/swapping of the parent and the child. It seems that the heapify is not working as I get back an array in the order of the way the numbers were inserted. Here is what I have so far.
private int getLeftChildIndex(int index)
{
return (2*index + 1);
}
private int getLeftChildValue(int index)
{
return heap[2*index + 1];
}
private int getRightChildIndex(int index)
{
return (2*index + 2);
}
private int getRightChildValue(int index)
{
return heap[2*index + 2];
}
private int getParentIndex(int index)
{
return ((int) Math.ceil((index - 2)/2));
}
private void swap(int child, int parent)
{
int temp = heap[parent];
heap[parent] = heap[child];
heap[child] = temp;
}
private void insert(int num)
{
heap[heapSize] = num;
heapSize++;
int index = heapSize - 1;
while (getParentIndex(index) > 0 && heap[index] > heap[getParentIndex(index)])
{
swap(index, getParentIndex(index));
index = getParentIndex(index);
}
}
public static void main(String[] args)
{
HeapTest heap = new HeapTest();
heap.insert(15);
heap.insert(5);
heap.insert(10);
heap.insert(30);
}
which just gives an array of the form [15,5,10,30] for example. This array for a max heap should be of the form [30,15,10,5]
Im expecting this: [15,5,10,30] -> [15,30,10,5] -> [30,15,10,5]
Could any one provide some insight as to why the heapify part of insert is not working?
Thanks!!
There are a couple of issues I can see.
consider what Math.ceil((index - 2)/2) would return for index 3. This would return 0 rather than 1 because the /2 is an integer operation. Changing that to /2.0 will fix it. Or even simpler would be to make use of integer arithmetic with (index - 1) / 2 which is clearer and more efficient.
getParentIndex(index) > 0 means that you are ignoring the root node at index 0 - currently your code will never swap that item. changing to >= will fix it.
There could well be other issues but those are 2 I can see by inspection. Either unit testing or interactive debugging would have uncovered those issues.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I am trying to use ArrayDeque for a class that is supposed to have O(1) time complexity for addfront, addback and retrieval. I could only think of using toArray() for retrieval and it is unfortunately O(n). Is there a way to implement a retrieval method for ArrayDeque that is O(1)?
No.
I looked through the source code of ArrayDeque, and in no place is there a method that accesses an arbitrary array element by index. This would have been required in order for the operation to perform in O(1).
It shouldn’t be too hard to implement your own class that fulfils your requirements, though. Search for “circular buffer”. If your array overflows, copy the entire contents into a new array of double size. This can’t be done in constant time, of course, but adding will still be in amortized constant time, the same as for ArrayDeque.
I have assumed that by get() you mean inspecting (without removing) an element by its position/index in the queue counted either from the front or from the back.
Edit
I guess another way would be to use array and find a way to make
addfront constant time but I'm not sure how
Here’s a simple implementation. Please develop further to your need. The ideas are to use a circular buffer and to copy to a new array if the old one gets too small. I believe that ArrayDeque uses the same ideas.
public class MyArrayDeque<E> {
private Object[] elements;
// Index to first element.
private int front = 0;
// Index to first free space after last element.
// back == front means queue is empty (not full).
private int back = 0;
public MyArrayDeque(int initialCapacity) {
if (initialCapacity < 0) {
throw new IllegalArgumentException("Initial capacity must not be negative");
}
// There’s always at least 1 free space, so add 1 to have room for initialCapacity elements
elements = new Object[initialCapacity + 1];
}
public void addFront(E elem) {
checkCapacity();
if (front == 0) {
front = elements.length - 1;
} else {
front--;
}
elements[front] = elem;
}
public void addBack(E elem) {
checkCapacity();
elements[back] = elem;
if (back == elements.length - 1) {
back = 0;
} else {
back++;
}
}
// Makes sure the queue has room for one more element.
private void checkCapacity() {
boolean needToExpand;
if (front == 0) {
needToExpand = back == elements.length - 1;
} else {
needToExpand = back == front - 1;
}
if (needToExpand) {
Object[] newElements = new Object[elements.length * 2];
if (front <= back) {
int size = back - front;
System.arraycopy(elements, front, newElements, 0, size);
front = 0;
back = size;
} else {
int numberOfElementsToCopyFirst = elements.length - front;
System.arraycopy(elements, front, newElements, 0, numberOfElementsToCopyFirst);
System.arraycopy(elements, 0, newElements, numberOfElementsToCopyFirst, back);
front = 0;
back = numberOfElementsToCopyFirst + back;
}
elements = newElements;
}
}
/** Gets the ith element counted from the front without removing it. */
public E get(int i) {
int index = front + i;
if (index >= elements.length) {
index -= elements.length;
}
boolean outOfRange;
if (front <= back) {
outOfRange = index < front || index >= back;
} else {
outOfRange = index >= back && index < front;
}
if (outOfRange) {
throw new ArrayIndexOutOfBoundsException(i);
}
return getInternal(index);
}
#SuppressWarnings("unchecked")
private E getInternal(int index) {
return (E) elements[index];
}
}
For a simple demonstration:
MyArrayDeque<String> queue = new MyArrayDeque<>(1);
queue.addFront("First element added");
queue.addBack("Added at back");
queue.addFront("Added at front");
System.out.println(queue.get(1));
Output is:
First element added
The ArrayDeque API doesn't provide any way to do this.
However, you could write a custom subclass of ArrayDeque that implements get. Something like this:
public E get(int i) {
if (i < 0 || i > size()) {
throw new ....("out of bounds");
}
long pos = this.head + i;
if (pos >= this.elements.length) {
pos -= this.elements.length;
}
return this.elements[(int) pos];
}
Note: this code has not been compiled / debugged. Use at your own risk!
This is O(1) and has no impact on the performance of the existing operations in the ArrayDeque API.
UPDATE
The above won't work as a subclass of the standard ArrayDeque class because the fields it is accessing are package private. However, you could copy the original class and add the above method to the copy.
(Just make sure that you copy the code from the OpenJDK codebase, and satisfy the GPLv2 requirements.)
You could achieve it using additional structure so the space complexity will become O(2n) which might not be very important.
The approach I could suggest is to use a HashMap and to store there an index and link of Object you put to queue. Also, you will need to keep track on first and last index available. Every time you will have to access the element by index - you will have to calculate the shift based on the start index. Of course, you will have to take care to update start and end indexes every time element is added or removed from the queue. The only disadvantage - removal from the middle may take O(n), which might not be critical for the queue case.
Here is an example with states of your objects while using additional structure:
indexMap: {}
startIndex:0
endIndex:0
--> add an element to the head
newCalculatedIndex = startIndex == endIndex ? startIndex : startIndex -1;
//newCalculatedIndex = 0
indexMap: {(0,'A')}
startIndex:0
endIndex:0
--> add an element to the head
//newCalculatedIndex = 0-1 = -1
indexMap: {(-1,'B'), (0,'A')}
startIndex:-1
endIndex:0
--> add an element to the tail
newCalculatedIndex = startIndex == endIndex ? endIndex : endIndex + 1;
//newCalculatedIndex = 0 + 1 = 1
indexMap: {(-1,'B'), (0,'A'), (1,'C')}
startIndex:-1
endIndex:1
--> Access element with index 2:
calculatedIndex = -1 + 2 = 1 -> indexMap.get(1) returns 'C'
I am trying to find the "maximum" value in a linked list recursively using a helper function. I am just starting to learn about these in my class and am pretty confused. We have a custom class that defines the type Node and another function to calculate the size of the Node or linkedlist. I solved this problem when I was comparing integers, but with characters I am lost. Here is my code:
'''
static class Node {
public Node (char item, Node next) { this.item = item; this.next = next; }
public char item;
public Node next;
}
Node first; // this is the only instance variable,
// the access point to the list
// size
//
// a function to compute the size of the list, using a loop
// an empty list has size 0
public int size () {
int count = 0;
for (Node tmp = first; tmp != null; tmp = tmp.next)
count++;
return count;
}
/*
* maxCharacter
*
* a function to compute the 'maximum' character in the list using recursion
* You will want to create a helper function to
* do the recursion
*
* precondition: list is not empty
*
* Examples:
* ["ababcdefb"].maxCharacter() == 'f'
* ["eezzg"].maxCharacter() == 'z'
* ["a"].maxCharacter() == 'a'
*/
public char maxCharacter () {
return maxCharacterHelper(first, first.size());
}
public char maxCharacterHelper(Node first, int index) {
char[] alpha = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
int max = 0;
while(index > 0 )
max = alpha.indexOf(first.item) > max ? first.item : max;
maxCharacterHelper(first, index-1);
return max;
}
'''
If you could explain how I would loop through the list recursively while maintaining the greatest char I would greatly appreciate it.
The golden rule with recursion is "Think of the base case first, then write the recurrence".
In this case, the base is the empty list. In this case, the maximum is the last value you've seen.
The recurrence is just a call to the rest of the list with the highest value you've called.
public static MaxNode(Node n, char currentMax) {
if (n == null) // base case, we're at the end.
return currentMax;
// recurrence
return MaxNode(n.next, currentMax > n.item ? currentMax : n.item);
}
For simple ASCII values, you can treat the maximum using the > operator.
Your while loop is confusing because of indentation and because you never change index. However, I don't think you need it if your intent is to use recursion. Generally with recursion you need to establish a base case from which you cannot recurse. For a linked list the natural base case is where there is no next node, rather than index-based.
if (current.next == null)
return alpha.indexOf(current.item);
Otherwise combine the recursion return with the current value
int remainingMax = maxCharacterHelper(current);
int currentValue = alpha.indexOf(current.item);
return (remainingMax > currentValue) ? remainingMax : currentValue;
Here is how I would put it together
//I made it static because it is not a method of a specific Node
public static int maxCharacterHelper(Node currentNode){
// remaining list includes only current node, so this one has max value
if (current.next == null)
return alpha.indexOf(current.item);
//otherwise take the larger of remaining list and current node
int remainingMax = maxCharacterHelper(current.next);
int currentValue = alpha.indexOf(current.item);
return (remainingMax > currentValue) ? remainingMax : currentValue;
}
I need to find the maximum value in a linked list given the head of the list as a parameter recursively. I have no clue how to start the recursive part of the method. This is all I have so far.
int maxOfList(List M){
List max = M;
if(M == null)
return max;
if(M.next > max){
max = M.restOfTheInts;
return maxOfList();
}
}
In recursion, you often need an entry method and a worker method. The entry method is the special case that allows the worker method to work in all cases, and the worker does the recursion.
For example, your worker might be something like:
int maxOfList(int currentMax, List<int> listToCheck) {
// Nothing to compare? currentMax is it!
if (listToCheck == null || listToCheck.size() == 0) return currentMax;
// Compare and return.
List<int> restOfList = listToCheck.subList(1, listToCheck.size());
return maxOfList(Math.max(currentMax, listToCheck.get(0)), restOfList);
}
And then to kick that off, you need your entry method:
int maxOfList(List<int> listToCheck) {
return maxOfList(Integer.MIN_VALUE, listToCheck);
}
So, for recursion to effectively work, you need to have the whole context visible inside the function.
int maxOfList(List m) {
if(m.next == null)
return m;
int previousMax = maxOfList(m.next);
if(m > previousMax)
return m;
else
return previousMax;
}
int maxValue(List m){
return maxValue(m, Integer.MIN_VALUE);
}
int maxValue(List m, int num){
if(m.next == null){
if(m.data > num)
return num = m.data;
}
return maxValue(m.next, num);
}
This should be pretty straightforward. In order to achieve a recursive solution, think about all these steps:
What's the recursive idea? The maximum of a list {L} is the max(Li, {L} - Li), where Li is the current element;
What's the stop condition? We know that if a list is empty, the maximum could be something that any number will be greater, let's say MIN_INT;
Putting all together: So, at the end we could say that a pseudo-code would look like this:
int maxOfList(List M) {
if(M == null)
return Integer.MIN_VALUE;
int max = maxOfList(M.next);
return M.value > max ? M.value : max;
}
I am supposing that the linked list has its content in value and points to next element in next (tail pointing to null). If you find any further problems, take a look at this posts:
Finding Max value in an array using recursion
Python: Recursive function to find the largest number in the list
I'm trying to create an array-based dequeue but I can't get the order of the output right.
Right now it is bounded but I will probably use unbounded once I figure out how to work the dequeue right.
Here is my code:
public class ArrayBndDequeue<T> implements BoundedDequeueInterface<T>
{
protected final int DEFCAP = 100; // default capacity
protected T[] queue; // array that holds queue elements
protected int numElements = 0; // number of elements n the queue
protected int front = 0; // index of front of queue
protected int rear; // index of rear of queue
public ArrayBndDequeue()
{
queue = (T[]) new Object[DEFCAP];
rear = DEFCAP - 1;
}
public ArrayBndDequeue(int maxSize)
{
queue = (T[]) new Object[maxSize];
rear = maxSize - 1;
}
public void enqueue(T element)
// Throws QueueOverflowException if this queue is full;
// otherwise, adds element to the front of this queue.
{
if (isFull())
throw new DequeueOverflowException("Enqueue attempted on a full queue.");
else
{
front = (front + 1) % queue.length;
queue[front] = element;
numElements = numElements + 1;
}
}
public T dequeue()
// Throws QueueUnderflowException if this queue is empty;
// otherwise, removes rear element from this queue and returns it.
{
if (isEmpty())
throw new DequeueUnderflowException("Dequeue attempted on empty queue.");
else
{
T toReturn = queue[rear];
queue[rear] = null;
rear = (rear + 1) % queue.length;
numElements = numElements - 1;
return toReturn;
}
}
public boolean isEmpty()
// Returns true if this queue is empty; otherwise, returns false
{
return (numElements == 0);
}
public boolean isFull()
// Returns true if this queue is full; otherwise, returns false.
{
return (numElements == queue.length);
}
}
And this is my main class:
public class Dequeue
{
public static void main(String[] args)
{
Scanner userInput = new Scanner(System.in);
String line;
BoundedDequeueInterface<String> queue;
queue = new ArrayBndDequeue<String>(3);
for (int i = 1; i <= 3; i++)
{
System.out.print("Enter a line of text > ");
line = userInput.nextLine();
queue.enqueue(line);
}
System.out.println("\nOrder is:\n");
while (!queue.isEmpty())
{
line = queue.dequeue();
System.out.println(line);
}
}
}
When I run the program, I usually type in:
1
2
3
And the output comes out as:
2
3
1
Any help? If you need anymore pieces of my code, just let me know!
During enqueue you are at first adding +1 to front, then set the object, but you need to do it the opposite order.
On the other hand it is a very bad idea to implement your own Queue class (unless you do it for learning of course), as Java already has a high-speed, reliable and well tested class for this. You can have a look at the source code of the Java queue class for ideas on how to do it properly.
The problem you describe stems from the following expression during insertion (equally applies to removal):
this.front = (this.front + 1) % this.queue.length;
This evalates to:
(0 + 1 % 3) = 1
(1 + 1 % 3) = 2
(2 + 1 % 3) = 0
Because as the third value is stored, due to the size of the queue being 3, you get 3 % 3 which is 0. So the value is stored at index 0.
Have a look at the definition of this algorithm in the ArrayDeque of the JDK. They do it like this:
public void addFirst(E e) {
if (e == null)
throw new NullPointerException();
elements[head = (head - 1) & (elements.length - 1)] = e;
if (head == tail)
doubleCapacity();
}
I think you meant the following (although your overall rational is correct)
Correction
(0+1) % 3 = 1
(1+1) % 3 = 2
(2+1) % 3 = 0
Instead of your example (since % operator has higher precedence order equivalent to multiplication or division from left to right):
(0 + 1 % 3) = 1 => 1
(1 + 1 % 3) = 2 => 2
(2 + 1 % 3) = 0 => 3