How to implement a PriorityQueue without using the Java class? - java

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.

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).

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(","));
}

Related

How to get the data from a file into an array?

Over the passed couple of hours I have been working on an assigment with no luck in figuring it out. For reference I am going to post the instructions below and then explain what I have done.
Write a Java class that implements the StringSet interface (see
attached text document). One of your instance variables must be an
array of Strings that holds the data; you may determine what, if any
other instance variables you need. You will also need to implement the
required methods, one or more constructors, and any other methods you
deem necessary. I have also provided a tester class that you should be
able to run your code with.
So far I have created an implementation of the interface named MyStringSet. I have put all of the methods from the interface into my implementation and have written the code to what I think will work. My main problem is that I don't know how to put the data from the main method that is called into an array. The user types in a file and and then it is supposed to return word count and other methods. Since the file is being called from the tester class, I need to store that data into an array or an array list which I have already created. Below I have listed my current implementation and the tester class that I use. Any help is greatly appreciated!
My Implementation:
public class MyStringSet implements StringSet {
String[] myArray = new String [] {};
List<String> myList = Arrays.asList(myArray);
//default constructor
public MyStringSet(){
resize(5);
}
// precondition: larger is larger than current Set size
// postcondition: enlarges Set
public void resize(int larger) {
myArray = Arrays.copyOf(myArray, myArray.length + larger);
}
// postcondition: entry is inserted in Set if identical String
// not already present; if identical entry exists, takes no
// action. Calls resize if necessary
public void insert(String entry) {
Set<String> myArray = new HashSet<String>();
Collections.addAll(myArray, entry);
}
// postcondition: removes target value from Set if target is
// present; takes no action otherwise
public void remove(String target) {
if(target != null){
int n = 0;
int index = n;
for(int i = index; i < myArray.length - 1; i++) {
myArray[i] = myArray[i+1];
}
}
}
// precondition: Set is not empty
// postcondition: A random String is retrieved and removed from
// the Set
public String getRandomItem () {
String s = "String is Empty";
if (myArray != null) {
int rnd = new Random().nextInt(myArray.length);
return myArray[rnd];
}
else {
return s ;
}
}
// precondition: Set is not empty
// postcondition: the first item in the Set is retrieved and
// removed from the Set
public String getFirstItem () {
String firstItem = myList.get(0);
return firstItem;
}
// postcondition: returns true if target is present, false
// if not
public boolean contains(String target) {
if (target == null) {
return false;
}
else {
return true;
}
}
// postcondition: returns true if Set is empty, false if not
public boolean is_empty( ) {
if(myArray == null){
return true;
}
else {
return false;
}
}
// postcondition: returns total number of Strings currently in set
public int inventory() {
int total = myList.size();
return total;
}
// postcondition: returns total size of Set (used & unused portions)
public int getCapacity( ) {
int capacity = myArray.length;
return capacity;
}
}
Tester class:
public class SetTester
{
public static void main(String [] args) {
StringSet words = new MyStringSet();
Scanner file = null;
FileInputStream fs = null;
String input;
Scanner kb = new Scanner(System.in);
int wordCt = 0;
boolean ok = false;
while (!ok)
{
System.out.print("Enter name of input file: ");
input = kb.nextLine();
try
{
fs = new FileInputStream(input);
ok = true;
}
catch (FileNotFoundException e)
{
System.out.println(input + " is not a valid file. Try again.");
}
}
file = new Scanner(fs);
while (file.hasNext())
{
input = file.next();
words.insert(input);
System.out.println("Current capacity: " + words.getCapacity());
wordCt++;
}
System.out.println("There were " + wordCt + " words in the file");
System.out.println("There are " + words.inventory() + " elements in the set");
System.out.println("Enter a value to remove from the set: ");
input = kb.nextLine();
while (!words.contains(input))
{
System.out.println(input + " is not in the set");
System.out.println("Enter a value to remove from the set: ");
input = kb.nextLine();
}
words.remove(input);
System.out.println("There are now " + words.inventory() + " elements in the set");
System.out.println("The first 10 words in the set are: ");
for (int x=0; x<10; x++)
System.out.println(words.getFirstItem());
System.out.println("There are now " + words.inventory() + " elements in the set");
System.out.println("5 random words from the set are: ");
for (int x=0; x<5; x++)
System.out.println(words.getRandomItem());
System.out.println("There are now " + words.inventory() + " elements in the set");
}
}
main problem is that I don't know how to put the data from the main method that is called into an array
You're doing that correctly already, following this simple example
StringSet words = new MyStringSet();
words.insert("something");
However, the contents of the insert method seem incorrect 1) you never check for identical values 2) never resizing 3) Collections.addAll doesn't do what you want, most likely
So, with those in mind, and keeping an array, you should loop over it, and check where the next non-null, non-identical value would be placed
// postcondition: entry is inserted in Set if identical String
// not already present; if identical entry exists, takes no
// action. Calls resize if necessary
public void insert(String entry) {
int i = 0;
while (i < myArray.length && myArray[i] != null) {
if (myArray[i].equals(entry)) return; // end function because found matching entry
i++;
}
if (i >= myArray.length) {
// TODO: resize()
insert(entry); // retry inserting same entry into larger array
}
// updates the next non-null array position
myArray[i] = entry;
}
As far as displaying the MyStringSet class goes, to see the contents of the array, you'll want to add a toString method

Trying to find a Unique Element in the ArrayList Implementation in Java. A getUnique Method

public class MyArrayList<T> implements MyList<T>{
int num; //number of things in the list
T[] vals; //to store the contents
#SuppressWarnings("unchecked")
public MyArrayList() {
num = 0;
vals = (T[]) new Object[3];
}
public T getUnique(){
T distinct = null;
int count = 0;
for (int i=0; i<vals.length; i++){
distinct = vals[i];
for (int j = 0; j<vals.length; j++){
if (vals[j] == vals[i]){
count++;
}
if (count == 1){
return distinct;
}
}
}
if (distinct == null){
throw new IllegalArgumentException();
}
return distinct;
}
I am trying to work on a get Unique Method. A method getUnique that takes no arguments and returns the first value in the list that appears only once. (For example, calling the method on the list [1,2,3,1,2,4] would return 3 since 1 and
2 both appear more than once.) If the list is empty or all its values appear more than once, the method throws a NoSuchElementException
I have added some FIXME's to your code:
public T getUnique(){
T distinct = null;
int count = 0; // FIXME: move this initialization inside the i loop
for (int i=0; i<vals.length; i++){
distinct = vals[i];
for (int j = 0; j<vals.length; j++){
if (vals[j] == vals[i]){ // FIXME: use .equals() not ==
count++;
}
if (count == 1){ // FIXME: move this check outside the j loop
return distinct;
}
}
}
if (distinct == null){ //FIXME: no check needed, just throw it
throw new IllegalArgumentException();
}
return distinct; //FIXME: no valid return can reach this point
}
Patrick Parker's advice will fix your code, but I wanted to provide a cleaner and faster solution to the problem of finding a unique element in a list. This algorithm runs in time O(n) instead of O(n^2).
public static <T> Optional<T> getUnique(List<T> ls) {
// Create a map whose keys are elements of the list and whose values are
// lists of their occurences. E.g. [1,2,3,1,2,4] becomes {1->[1, 1],
// 2->[2, 2], 3->[3], 4->[4]}. Then elements.get(x).size() tells us how
// many times x occured in ls.
Map<T, List<T>> elements = ls.stream()
.collect(Collectors.groupingBy(x -> x));
// Find the first element that occurs exactly one time in ls.
return ls.stream().filter(x -> elements.get(x).size() == 1)
.findFirst();
}
You might call it like this:
Integer[] vals = {1,2,3,1,2,4};
System.out.println(getUnique(Arrays.asList(vals))
.orElseThrow(NoSuchElementException::new));
This code uses Java 8 streams and Optional. Below is another implementation of the same algorithm that doesn't use Java 8 language features; if you've never encountered streams, you may find it more understandable.
private static <T> T getUnique(List<T> arr) {
Map<T, Integer> numOccurrences = new HashMap<>();
for (T item : arr) {
numOccurrences.put(item, 1 + numOccurrences.getOrDefault(item, 0));
}
for (T item : arr) {
if (numOccurrences.get(item) == 1) {
return item;
}
}
throw new NoSuchElementException();
}

Recursive Search Function Java

public int search(String type) {
for (int i = 0; i < size; i++) {
if (array[size-1-i].contains(type)) return i;
}
return -1;
}
I am having trouble doing a recursive function of this previous search function , can somebody help me ?
For a recursive function, a simple solution would be to pass in the value you want to search and the index to search at as parameters to the function.
Then you check
if the index passed in is greater than length of array , then return -1 (since we were not able to find the element.
if you can find the value pass in at the index passed in, if yes, just return that index ,
if not above 2 , then try to search it at next index.
For this recursive function, start at index 0 , by passing 0 when calling the function.
Example code -
public int search(String type, int index) {
if (index >= array.length) {
return -1;
}
else if(array[index].contains(type)) {
return array.length - i + 1; # assuming size from your function is array.length
}
else {
return search(type, index + 1)
}
}
It seems you want to write a recursive variant of this search function. I am not doing any optimization in your code as you need to take care of that. I have assumed few things to make your code compile and here is the code I have tried:
static String[] array = new String[] {"John", "Sam", "David"};
static int size = array.length;
public static void main(String[] args) {
int index = searchRecursive(0,"Sam");
System.out.println("Index: " + index);
}
public static int searchRecursive(int indexToCheck, String type) {
int result = -1;
if(indexToCheck<size) {
if(array[size-1-indexToCheck].contains(type)) {
result = indexToCheck;
} else {
result = searchRecursive(indexToCheck+1,type);
}
}
return result;
}
public static int searchIterative(String type) {
for (int i = 0; i < size; i++) {
if (array[size-1-i].contains(type)) return i;
}
return -1;
}

Sorting a integer list without a sort command

So I have this code:
public class SortedIntList extends IntList
{
private int[] newlist;
public SortedIntList(int size)
{
super(size);
newlist = new int[size];
}
public void add(int value)
{
for(int i = 0; i < list.length; i++)
{
int count = 0,
current = list[i];
if(current < value)
{
newlist[count] = current;
count++;
}
else
{
newlist[count] = value;
count++;
}
}
}
}
Yet, when I run the test, nothing prints out. I have the system.out.print in another class in the same source.
Where am I going wrong?
EDIT: Print code from comment:
public class ListTest
{
public static void main(String[] args)
{
SortedIntList myList = new SortedIntList(10);
myList.add(100);
myList.add(50);
myList.add(200);
myList.add(25);
System.out.println(myList);
}
}
EDIT2: Superclass from comment below
public class IntList
{
protected int[] list;
protected int numElements = 0;
public IntList(int size)
{
list = new int[size];
}
public void add(int value)
{
if (numElements == list.length)
System.out.println("Can't add, list is full");
else {
list[numElements] = value; numElements++;
}
}
public String toString()
{
String returnString = "";
for (int i=0; i<numElements; i++)
returnString += i + ": " + list[i] + "\n";
return returnString;
}
}
Let's walk through the logic of how you want it to work here:
first you make a new sorted list passing 10 to the constructor, which make an integer array of size 10.
now you call your add method passing 100 into it. the method sets position 0 to 100
now you add 50, the method sets 50 in position 0 and 100 in position 1
now you add 200, which gets placed at position 2
and you add 25. which gets set to position 0, and everything else gets shuffled on down
then your method will print out everything in this list.
So here are your problems:
For the first add, you compare current, which is initialized at 0, to 50. 0 will always be less than 50, so 50 never gets set into the array. This is true for all elements.
EDIT: Seeing the super class this is how you should look to fix your code:
public class SortedIntList extends IntList
{
private int[] newlist;
private int listSize;
public SortedIntList(int size)
{
super(size);
// I removed the newList bit becuase the superclass has a list we are using
listSize = 0; // this keeps track of the number of elements in the list
}
public void add(int value)
{
int placeholder;
if (listSize == 0)
{
list[0] = value; // sets first element eqal to the value
listSize++; // incriments the size, since we added a value
return; // breaks out of the method
}
for(int i = 0; i < listSize; i++)
{
if (list[i] > value) // checks if the current place is greater than value
{
placeholder = list[i]; // these three lines swap the value with the value in the array, and then sets up a comparison to continue
list[i] = value;
value = placeholder;
}
}
list[i] = value; // we are done checking the existing array, so the remaining value gets added to the end
listSize++; // we added an element so this needs to increase;
}
public String toString()
{
String returnString = "";
for (int i=0; i<listSize; i++)
returnString += i + ": " + list[i] + "\n";
return returnString;
}
}
Now that I see the superclass, the reason why it never prints anything is clear. numElements is always zero. You never increment it because you never call the superclass version of the add method.
This means that the loop in the toString method is not iterated at all, and toString always just returns empty string.
Note
This is superseded by my later answer. I have left it here, rather than deleting it, in case the information in it is useful to you.
Two problems.
(1) You define list in the superclass, and presumably that's what you print out; but you add elements to newList, which is a different field.
(2) You only add as many elements to your new list as there are in your old list. So you'll always have one element too few. In particular, when you first try to add an element, your list has zero elements both before and after the add.
You should probably have just a single list, not two of them. Also, you should break that for loop into two separate loops - one loop to add the elements before the value that you're inserting, and a second loop to add the elements after it.

Searching through an ArrayList of Strings to find text

This is what I have so far but I don't now what to do next. The question is as follows (sorry the coding is not all appearing in one box):
Implement a method
public void search (String searchString) { }
to iterate through the notes ArrayList until it finds a note that contains the searchString. It should then print either the item found or the message "String not found". When testing check for a String that is in the list and for one that isn't.
Code:
import java.util.ArrayList;
import java.util.Iterator;
/**
* A class to maintain an arbitrarily long list of notes.
* Notes are numbered for external reference by a human user.
* In this version, note numbers start at 0.
*
* #author David J. Barnes and Michael Kolling.
* #version 2008.03.30
*/
public class Notebook
{
// Storage for an arbitrary number of notes.
private ArrayList<String> notes;
/**
* Perform any initialization that is required for the
* notebook.
*/
public Notebook()
{
notes = new ArrayList<String>();
}
/**
* Store a new note into the notebook.
* #param note The note to be stored.
*/
public void storeNote(String note)
{
notes.add(note);
}
/**
* #return The number of notes currently in the notebook.
*/
public int numberOfNotes()
{
return notes.size();
}
/**
* Show a note.
* #param noteNumber The number of the note to be shown.
*/
public void showNote(int noteNumber)
{
if(noteNumber < 0) {
// This is not a valid note number, so do nothing.
System.out.println("invalid index given");
}
else if(noteNumber < numberOfNotes()) {
// This is a valid note number, so we can print it.
System.out.println(notes.get(noteNumber));
}
else {
System.out.println("there are fewer items in the notebook than that");
// This is not a valid note number, so do nothing.
}
}
public void removeNote(int noteNumber)
{
if(noteNumber < 0) {
// This is not a valid note number, so do nothing.
System.out.println("invalid index given");
}
else if(noteNumber < numberOfNotes()) {
// This is a valid note number.
notes.remove(noteNumber);
}
else {
System.out.println("there are fewer items in the notebook than that");
// This is not a valid note number, so do nothing.
}
}
public void multiplesOfFive()
{
int i = 10;
while(i < 100)
{
System.out.println(i);
i = i + 5;
}
}
public int sum(int a, int b)
{
int index = a;
int result = 0;
while(index <= b)
{
result = result + index;
index = index + 1;
}
return result;
}
public int product(int a, int b)
{
int index = a;
int result = 1;
while(index <= b)
{
result = result * index;
index = index + 1;
}
return result;
}
public boolean
isPrime (int n)
{
if (n<=1)return false;
if (n==2) return true;
for (int i = 2;i<=n-1;i++)
{
if (n%i==0)return false;
}
return true;
}
}
two ideas to consider:
When you compose your search method, consider utilizing the contains method in the String class as you iterate (see Kaleb Brasee's post).
ensure that you handle the case when a null is passed in as the search param.
Use one of the new for-each style loops to iterate over the List of notes:
for (String string : notes) {
// This will loop over all the Strings in the notes List.
// Perform your logic here.
}
If the list is not in alphabetical order you need to loop through the list comparing each string against the search string. Once you find a match you can break the loop (using a return true (or the string) would be the easiest way) then outside the loop you can place a return false to signify that a match was not found.
Some methods you will need to use:
ArrayList:
size() - gives you the size of the list so you know when you have reached the end
get( int index ) - returns the item in the list at the specified index
String: equals( String cmp ) - compares 2 strings and returns an int
It would be good to become familiar with the Java API so that you can find methods and their return values.
If the list is in alphabetical order there are more efficient ways to search.

Categories

Resources