0

I'm trying to make a PriorityQueue without using the PriorityQueue class provided by Java. For this, I have some given methods that I have to fill in. I'm not sure where I'm making the mistake. It seems that my put and get functions are both wrong, and I'm not sure how to make a new PQ as is given in the code. What I have is the following:

class Element {

private int priority;
private String data;

Element(int priority, String data) { 
    // Ihr Code
    this.priority = priority;
    this.data = data;

 }

public String getData() { 
    // Ihr Code
    return data;
}


public int getPriority() { 
    // Ihr Code
    return priority;
 }

/**
 * Return data and priority as string 
 * Format: Data (Priority)
 * e.g: abc (7)
 */
public String toString()        {
    String str = data + " " + Integer.toString(priority) + ")";  
    return str;
}
}


public class PriorityQueue {


static final int SIZE = 32;


private Element[] data = null;

// actual number of entries
private int len = 0;


/**
 * Creates a new PriorityQueue
 */
public PriorityQueue() {
    // Ihr Code      
}

/** 
 * Adds a new element into the queue as long as there is space
 * Returns true if element could be added, otherwise false 
 */
boolean put(Element element) {
    // Ihr Code
    if(len == SIZE){
        return false;
    }else{
        int i = len-1;
        while (i>=0 && element.getPriority() > data[i].getPriority()){
            data[i+1] = data[i];
            i--;
        }
        data[i+1] = element;
        len++;
        return true;
    }

}

/**
 * Returns element with the highest priority 
 * and removes it from the queue. Otherwise returns null
 * 
 */
Element get() {
    // Ihr Code
    if (len > 0){
        Element x = q[0];
        for(int i = 1; i < len; i++){
            data[i-1] = data[i];
        }
        len--;
        return x;
        }else{
             return null;
        }
    }

/**
 * Number of entries 
 */
int length() {
    // Ihr Code
    return len;
 }

/**
 * Returns contents of the queue as a String
 * Format: data1 (priority1), data2 (priority2)
 * e.g: abc (7), cde (8)
 * Attention: There should be no comma at the end of the String 
 */
public String toString() {
    //  Code
    String res = new String();
    //res = "(" + data + "," + ")";

    if(data.length>0){
        StringBuilder sb = new StringBuilder();

        for(String s: data){
            sb.append(s).append(",");
        }
        res = sb.deleteCharAt(sb.length()-1).toString;
    }

    return res;
 }

I'm also struggling with the final toString method, to return the queue as a String in the format given, I tried something with a StringBuilder, but this doesn't compile correctly. Alternatively, I could make it with a normal for loop, but again I'm struggling with the exact syntax.

I found resources on the net to build this PQ with heap structures (which I have not had yet) and with a class called Comparator that I failed to understand. Any help would be much appreciated!

I'm mainly struggling with the

public PriorityQueue(){
      //what code?}

function. How am I supposed to make a "new" PQ here? Is it supposed to be

PriorityQueue pq = new PriorityQueue(); 

I'm quite lost! Thanks so much for the help.

1
  • Have you looked at the max-heap datastructure? This will be useful for this implementation. Commented Nov 5, 2019 at 18:49

2 Answers 2

1

Your PriorityQueue constructor has to initialize the array and set the current number of items. That is:

public PriorityQueue() {
    data = /* initialize array */
    len = 0;
}

You really don't need to keep the elements in the queue in order. Just make your put method add the item as the next element in the array:

public put(Element e) {
    if (len == SIZE) {
        return false;
    }
    data[len++] = e;
    return true;
}

And then your get method searches the array for the highest-priority item, saves it, replaces that with the item at the end of the array, and returns:

Element get() {
    if (len == 0) {
        return null;
    }
    int p = 0;
    for (int i = 1; i < len; ++i) {
        if (data[i].getPriority() < data[p].getPriority()]) {
            p = i;
        }
    }
    Element e = data[p];
    // replace with the last item
    data[p] = data[len-1];
    --len;
    return e;
}

So put is an O(1) operation and get is O(n). In your code, both are O(n).

Sign up to request clarification or add additional context in comments.

Comments

1

The constructor just needs to initialise the Element[]:

public PriorityQueue() {
    data = new Element[SIZE];
}

Now to put(). This method will throw an ArrayOutOfBoundsException in the while loop since you start with i = len - 1 which is the last field of data. Then you access data[i+1] which does not exist, and the exception will be thrown (unless, of course, you initialise it with data = new Element[SIZE + 1]).

Solution: just use i and i-1 instead:

boolean put(Element element) {
    if (len == SIZE) {
        return false;
    } else {
        // EDIT: I changed i = len - 1 to i = len since, otherwise,
        // the last element would always be overwritten. Now, the
        // last element gets copied to the first "free" element and
        // so on.
        i = len;
        while (i > 0 && element.getPriority() > data[i-1].getPriority()) {
            data[i] = data[i - 1];
            i--;
        }
        data[i] = element;
        len++;
        return true;
    }
}

EDIT: I said before that the element with the smallest priority would be returned. Actually, it is the greatest.

The get() method behaves as expected (except it should say Element x = data[0] instead of q[0] at the beginning). It returns the first element of the array (the one with the greatest getPriority() value) and moves the rest one index down. If, however, you want the element with the smallest value to be returned, just switch the > to < in the while loop of the put() method:

while (i > 0 && element.getPriority() < data[i-1].getPriority()) {
    ...
}

Last but not least, the toString() method. It looks mostly right, except for the for-each loop. This one always iterates over the whole array where it should only iterate up to data[len - 1]. So, just use an index instead and you should be fine:

public String toString() {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < len; i++) {
        sb.append(data[i]).append(",");
    }
    if (sb.length() > 0) {
        sb.deleteCharAt(sb.length() - 1);
    }

    return sb.toString();
}

Alternatively, if you have at least Java 8 installed, you can use streams for this method:

public String toString() {
    return Arrays.asList(data).stream()
        .limit(len)
        .map(Element::toString)
        .collect(Collectors.joining(","));
}

6 Comments

Hey, thanks so much for the answer. Your explanation makes total sense and I noticed the toString() mistake myself. As for the rest of the code, I changed it to how you explained, but unfortunately it doesn't seem like it passes the tests that this assignment was given with. org.junit.ComparisonFailurefor the get and put tests. The toString() method is correct, but only with me changing the data[i] = element to data[i+1] = element in the put method. There is some sort of issues with the indexes I think. Any further help would massively appreciated! Thanks.
Okay, so I had to change the if statement to get the tests to work, but now they do. Unfortunately, me changing the if statement has made the toString test not pass anymore as it did before I changed my statement. I cannot paste the code here as I'm going over the character limit, but I changed the else in the putmethod to an else if (len > 0 && len < 32) and it worked. Do you have any idea why the toString method doesn't work anymore? I cannot get the Strings to even print from my main method. Thanks so much for the help! ```
Uhh, it seems it was already late yesterday, lol. I made some mistakes in my code. I'm gonna update my answer and put in the correct code (which, this time, I tested). Also, I was mistaken when I said that get() returns the smalles priority value. It returns the greatest.
Thanks for the edit! The get and put methods are correct according to my test cases, but unfortunately, the toString method is still failing. For some reason, I cannot get the data array to print on to the console, or to pass the tests. It worked with a previous version of the code, where put and get didn't work, but now that those 2 work, the toStringdoesn't. Extremely confused. Is there a possibilty you could look at the toString method again and help me out? I'm confused as to why nothing is being printed at all.
Hmm... I tested it using javac and java commands directly from PowerShell (with an additional main method) and it worked like a charm. What are you running it on? A console as well or inside an IDE (eclipse, NetBeans, IntelliJ, ...)? Also, what exactly does the test look like? (I suppose it's a JUnit test?)
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.