I have an exercise, where I have to implement a priority queue, using a min-heap.
However I cannot use the PriorityClass library, I have to implement it, by myself.
I've managed to do it by far, but, my professor, told me that my insert methods is wrong. He told me, to create an Element class, which contains 2 attributes of type T.These two attributes are (T element and T priority). How can I edit my insert method?
package priorityQueue;
import java.util.ArrayList;
import java.util.Comparator;
import priorityQueueInterfaces.PriorityQueue;
public class BinaryHeap<T> implements PriorityQueue<T>
{
private int currentSize = 0;
private static final int DEFAULT_CAPACITY = 20;
private ArrayList<T> array = null;
private Comparator <? super T> comparator = null;
/**
* Constructor of binary-heap
*/
public BinaryHeap(Comparator <? super T> comparator)
{
currentSize = 0;
array = new ArrayList<>(DEFAULT_CAPACITY + 1);
this.comparator = comparator;
}
/**
* Construct the binary heap from an arrayList
*/
public BinaryHeap(ArrayList<T> array, Comparator <? super T> comparator)
{
this.currentSize = array.size();
this.array = new ArrayList<>(array.size() + 1);
this.comparator = comparator;
for(int i = 0; i < array.size(); i++)
this.array.set(i + 1, array.get(i));
}
/**
* Method which builds the min heap with the minHeapify method
* #throws PriorityQueueException
*/
public void buildMinHeap(ArrayList<T> array, int heapSize) throws PriorityQueueException
{
for(int i = this.currentSize / 2; i > 0;i--)
minHeapify(this.array,i,this.currentSize);
}
/**
* Method which builds the max heap with the maxHeapify method
* #throws PriorityQueueException
*/
public void buildMaxHeap() throws PriorityQueueException
{
for(int i = this.currentSize/2; i > 0; i--)
maxHeapify(this.array,i,this.currentSize);
}
public void buildMaxHeap(ArrayList<T> array, int heapSize)throws PriorityQueueException
{
if(this.array == null)
throw new NullPointerException("ArrayList is null");
if(this.array.size() <= 0 || heapSize <= 0 )
throw new IllegalArgumentException("Illegal Parameters: either the arraylist or the heap size are not valid");
if(heapSize > this.array.size())
heapSize = this.array.size();
for(int i = heapSize/2; i > 0; i--)
maxHeapify(this.array,i,heapSize);
}
/**
* Insert into the priority queue.
* Duplicates are allowed.
* #param element is the item to insert.
*/
public void insert(T element) throws PriorityQueueException
{
if(element == null)
throw new IllegalArgumentException("Element to be inserted, cannot be null!");
if(this.size() + 1 == this.array.size())
extendArray();
this.currentSize = this.size() + 1;
if(this.isEmpty())
this.array.add(0,element);
else
{
this.array.add(element);
int index = this.size() - 1;//indice index = all'elemento appena aggiunto
while( index > 1 && this.comparator.compare(this.array.get(index/2), this.array.get(index)) < 0)
{
swapElements(index, index/2);
index = index / 2;
}
}
}
/**
* #param firstIndex of the element that has to be swapped
* #param secondIndex of the element that has to be swapped
* #throws PriorityQueueException
*/
private void swapElements(int firstIndex,int secondIndex)throws PriorityQueueException
{
T temp = this.array.get(firstIndex);
this.array.set(firstIndex, this.array.get(secondIndex));
this.array.set(secondIndex,temp);
}
}
THAT'S MY ELEMENT CLASS Which I have to use for adding an element with min-priority
package priorityQueue;
public class Element<T>
{
private T element;
private T priority;
public Element(T element,T priority)
{
this.element = element;
this.priority = priority;
}
public void setElement(T element)
{
this.element = element;
}
public void setPriority(T priority)
{
this.priority = priority;
}
public T getElement()
{
return this.element;
}
public T getPriority()
{
return this.priority;
}
}
My method of insert works just fine, but i have to insert also the priority contained in the class element. How to do it?
Related
This question already has an answer here:
Generics in Java, Merge method
(1 answer)
Closed 6 years ago.
Here is my question:
A method named merge that concatenates 2 unordered lists into a third. Assume that list_1 and list_2 don't have any keys in common. The resulting list should be an unsorted list that contains all of the items from list_1 and list_2 (preserve the order).
The problem that I am having is that I need to answer this question using generics. I have the code for the normal merge method which is the following..
// Merge Method
public OrderedArrayList merge(OrderedArrayList list2){
OrderedArrayList result = new OrderedArrayList(length + list2.length);
int list1Index = 0;
int list2Index = 0;
for (int i = 0; i < result.maxSize; i++) {
if (list1Index == list.length) {
result.insert(list2.list[list2Index]);
list2Index++;
} else if (list2Index == list2.length) {
result.insert(list[list1Index]);
list1Index++;
} else if (list[list1Index] < list2.list[list2Index]) {
result.insert(list[list1Index]);
list1Index++;
} else {
result.insert(list2.list[list2Index]);
list2Index++;
}
}
return result;
}
I have been working on the generics section for days. SOS!!
Here are my classes:
//Interface: ArrayListADT
//works for int
public interface ArrayListADT1<T> extends Comparable{
public boolean isEmpty(); //Method to determine whether the list is empty.
public boolean isFull(); //Method to determine whether the list is full.
public int listSize(); //Method to return the number of elements in the list.
public int maxListSize(); //Method to return the maximum size of the list.
public void print(); //Method to output the elements of the list.
public boolean isItemAtEqual(int location, T item); //Method to determine whether item is the same as the item in the list at location.
public void insertAt(int location, T insertItem); //Method to insert insertItem in the list at the position
public void insertEnd(T insertItem); //Method to insert insertItem at the end of the list.
public void removeAt(int location); //Method to remove the item from the list at location.
public T retrieveAt(int location); //Method to retrieve the element from the list at location.
public void replaceAt(int location, T repItem); //Method to replace the element in the list at location with repItem.
public void clearList(); //Method to remove all the elements from the list.
public int search(T searchItem); //Method to determine whether searchItem is in the list.
public void remove(T removeItem); //Method to remove an item from the list.
}
//Class: ArrayListClass1<T> implements
//Interface: ArrayListADT
public abstract class ArrayListClass1<T> implements ArrayListADT1<T>, Comparable{
protected int length; // to store the length of the list
protected int maxSize; // to store the maximum size of the list
protected T[] list; // array to hold the list elements
// Default constructor
public ArrayListClass1() {
maxSize = 100;
length = 0;
list = (T[]) new Object[maxSize];
}
// Alternate Constructor
public ArrayListClass1(int size) {
if (size <= 0) {
System.err.println("The array size must be positive. Creating an array of size 100.");
maxSize = 100;
} else
maxSize = size;
length = 0;
list = (T[]) new Object[maxSize];
}
public boolean isEmpty() {
return (length == 0);
}
public boolean isFull() {
return (length == maxSize);
}
public int listSize() {
return length;
}
public int maxListSize() {
return maxSize;
}
public void print() {
for (int i = 0; i < length; i++)
System.out.print(list[i] + " ");
System.out.println();
}
public boolean isItemAtEqual(int location, T item) {
if (location < 0 || location >= length) {
System.err.println("The location of the item to be compared is out of range.");
return false;
}
return list[location] == item;
}
public void clearList() {
for (int i = 0; i < length; i++)
list[i] = null;
length = 0;
System.gc(); // invoke the Java garbage collector
}
public void removeAt(int location) {
if (location < 0 || location >= length)
System.err.println("The location of the item to be removed is out of range.");
else {
for (int i = location; i < length - 1; i++)
list[i] = list[i + 1];
length--;
}
}
public T retrieveAt(int location) {
if (location < 0 || location >= length) {
System.err.println("The location of the item to be retrieved is out of range.");
return null;
} else
return list[location];
}
public abstract void insertAt(int location, T insertItem);
public abstract void insertEnd(T insertItem);
public abstract void replaceAt(int location, T repItem);
public abstract int search(T searchItem);
public abstract void remove(T removeItem);
}
//Class: OrderedArrayList1 extends
//Super class: ArrayListClass
public class OrderedArrayList1<T> extends ArrayListClass1<T>{
public OrderedArrayList1() {
super();
}
public OrderedArrayList1(int size) {
super(size);
}
// implementation for abstract methods defined in ArrayListClass
// ordered list --> binary search
public int search(T item) {
int first = 0;
int last = length - 1;
int middle = -1;
while (first <= last) {
middle = (first + last) / 2;
Comparable<T> listElem = (Comparable<T>) list[middle];
if (listElem.compareTo(item)==0)
return middle;
else
if (listElem.compareTo(item) > 0)
last = middle - 1;
else
first = middle + 1;
}
return -1;
}
public void insert(T item) {
int loc;
boolean found = false;
if (length == 0) // list is empty
list[length++] = item; // insert item and increment length
else if (length == maxSize) // list is full
System.err.println("Cannot insert in a full list.");
else {
for (loc = 0; loc < length; loc++) {
Comparable<T> temp = (Comparable<T>) list[loc];
if (temp.compareTo(item) >= 0) {
found = true;
break;
}
}
// starting at the end, shift right
for (int i = length; i > loc; i--)
list[i] = list[i - 1];
list[loc] = item; // insert in place
length++;
}
}
/*
* Another version for insert:
* public void insert(int item) {
* int loc;
* boolean found = false;
* if (length == 0) //list is empty
* list[length++] = item; //insert item and increment length
* else if (length == maxSize) //list is full
* System.err.println("Cannot insert in a full list.");
* else {
* int i = length - 1;
* while (i >= 0 && list[i] > item) {
* list[i + 1] = list[i];
* i--;
* }
* list[i + 1] = item; // Insert item
* length++;
* }
* }
*/
public void insertAt(int location, T item) {
if (location < 0 || location >= maxSize)
System.err.println("The position of the item to be inserted is out of range.");
else if (length == maxSize) // the list is full
System.err.println("Cannot insert in a full list.");
else {
System.out.println("Cannot do it, this is a sorted list. Doing insert in place (call to insert).");
insert(item);
}
}
public void insertEnd(T item) {
if (length == maxSize) // the list is full
System.err.println("Cannot insert in a full list.");
else {
System.out.println("Cannot do it, this is a sorted list. Doing insert in place (call to insert).");
insert(item);
}
}
public void replaceAt(int location, T item) {
// the list is sorted!
// is actually removing the element at location and inserting item in place
if (location < 0 || location >= length)
System.err.println("The position of the item to be replaced is out of range.");
else {
removeAt(location);// method in ArrayListClass
insert(item);
}
}
public void remove(T item) {
int loc;
if (length == 0)
System.err.println("Cannot delete from an empty list.");
else {
loc = search(item);
if (loc != -1)
removeAt(loc);// method in ArrayListClass
else
System.out.println("The item to be deleted is not in the list.");
}
}
/*
* Another version for remove:
* public void remove(T item) {
* int loc;
* if (length == 0)
* System.err.println("Cannot delete from an empty list.");
* else {
* loc = search(item);
* if (loc != -1) {
* for(int i = loc; i < length - 1; i++)
* list[i] = list[i + 1]; //shift left
* length--;
* }
* else
* System.out.println("The item to be deleted is not in the list.");
* }
* }
*/
/*
*
* KATHERINE'S
*
*/
// The start of Assignment 3
// Merge Method
public OrderedArrayList1<T> merge(OrderedArrayList1<T> list2){
OrderedArrayList1 result = new OrderedArrayList1(length + list2.length);
int list1Index = 0;
int list2Index = 0;
for (int i = 0; i < result.maxSize; i++) {
Comparable<T> temp = (Comparable<T>)list[list1Index];
T [] temp1 = new T list2[list1Index];
if (list1Index.equals(list[list1Index])) {
result.insert(list2.list[list2Index]);
list2Index++;
} else if (list2Index.equals(list[list1Index])) {
result.insert(list[list1Index]);
list1Index++;
}else if (temp.compareTo(list2) < 0) {
result.insert(list[list1Index]);
list1Index++;
} else {
result.insert(list2.list[list2Index]);
list2Index++;
}
}
return result;
}
// Split Method
public <T extends Comparable<T> > void split(OrderedArrayList1<T> lessThanKey, OrderedArrayList1<T> greaterThanKey, T splitKey) {
int i;
for (i = 0; i < length; i++) {
T temp = (T)list[i];
if (temp.compareTo(splitKey)<0)
lessThanKey.insert(temp);
else
greaterThanKey.insert(temp);
}
}
}
I have been working on the Merge Generics method for around 12 hours now. I have tried sooo many different ways. I would REALLY appreciate some help. Thank you!
Let's tackle this step by step.
First, you need to merge two lists together. This is only possible if the lists contain elements of the same type and, logically, the result will be a new list of the same type. So, we end up with the following method:
public <T extends Comparable<T>> List<T> merge(List<T> first, List<T> second) {
final List<T> merged = new ArrayList<T>();
merged.addAll(first);
merged.addAll(second);
return merged;
}
You just need to use your custom list implementation, but the principle is the same.
Second, when implementing your list, don't extend Comparable. You should only need that if you need to compare the instances of your class. Instead, make the elements comparable like in the example method.
I'm hoping to find a bit of direction for this problem I was given. Been banging my head over it for two weeks now. Essentially, I'm to write a function, public static int FindWords(char[][] puzzle) , where given a 2D char array, I can find the amount of times a given set of strings occur. Given:
public static class PuzzleSolver
{
public static string[] DICTIONARY = {"OX","CAT","TOY","AT","DOG","CATAPULT","T"};
static bool IsWord(string testWord)
{
if (DICTIONARY.Contains(testWord))
return true;
return false;
}
}
A 2D Array for instance that is like this:
public static char[][] puzzle = {{'C','A','T'},
{'X','Z','T'},
{'Y','O','T'}};
Would return back 8 for the following instances: (AT, AT, CAT, OX, TOY, T, T, T) because we would be searching horizontally, vertically, diagonally and in reverse for all the same directions.
My approach was to visit each char in the array and then search for all possible directions with the SearchChar function...
public static int FindWords(char[][] puzzle){
int arrayRow = puzzle.length;
int arrayCol = puzzle[0].length;
int found = 0;
for(int i = 0; i < arrayRow; i++){
for(int j = 0; j < arrayCol; j++){
found += SearchChar(i,j);
}
}
return found;
}
Which looks like this:
public static int SearchChar(int row, int col){
if(row < 0 || col < 0 || row > puzzle.length || col > puzzle[0].length)//Is row or col out of bounds?
return 0;
if(IsWord(puzzle[row][col]))
return 1;
return 0;
}
Conceptually, I feel like I need some kind of recursive function to handle this but I can't seem to wrap my head around it. I don't even know if that's the right approach. I've been playing around with StringBuilder appending but I'm still struggling with that too. I think this recursive function would need to take for instance, puzzle[0][0] (or 'C') and see if it is in the dictionary. Followed by puzzle[0][0] + puzzle[0][1] (or 'CA') and then finally puzzle[0][0] + puzzle[0][1] + puzzle[0][2] (or 'CAT'). Then the same would have to be don vertically and diagonally. I'm having trouble trying to get back into the SearchChar function with a position change to append to the original char so that I can see if it is in the DICTIONARY.
Sorry if this is a bit wordy, but I just want to give the impression that I'm actually trying to solve this. Not just some lazy programmer that's copy & pasting some problem up here for someone else to solve. Thanks in advance for any help!
I will show you how to solve this problem step by step.
1. Generating All Possible Words from the given Puzzle
to do this we must start anywhere in the puzzle and move towards all directions (except the previous Point) to generate all possible words;
2. Choosing Suitable Data Structure for Dictionary
I think Trie is a good choice and is suitable for use in such situations.
The most important reason for choosing Trie is that during the search, we can easily test if a word exists in our dictionary or is there any word that starts with the word generated by searching through the puzzle or not.
As a result, we can decide whether or not to continue the search.
This will save us a lot of time and helps to generate words correctly.
otherwise, we'll be stuck in an endless loop...
3. Implementation
there are several implementations for Tire , but I wrote my own CharTrie :
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
/**
* #author FaNaJ
*/
public final class CharTrie {
/**
* Pointer to root Node
*/
private final Node root = new Node();
/**
* Puts the specified word in this CharTrie and increases its frequency.
*
* #param word word to put in this CharTrie
* #return the previous frequency of the specified word
*/
public int put(String word) {
if (word.isEmpty()) {
return 0;
}
Node current = root;
for (int i = 0; i < word.length(); i++) {
current = current.getChildren().computeIfAbsent(word.charAt(i), ch -> new Node());
}
return current.getAndIncreaseFrequency();
}
/**
* #param word the word whose frequency is to be returned
* #return the current frequency of the specified word or -1 if there isn't such a word in this CharTrie
*/
public int frequency(String word) {
if (word.isEmpty()) {
return 0;
}
Node current = root;
for (int i = 0; i < word.length() && current != null; i++) {
current = current.getChildren().get(word.charAt(i));
}
return current == null ? -1 : current.frequency;
}
/**
* #param word the word whose presence in this CharTrie is to be tested
* #return true if this CharTrie contains the specified word
*/
public boolean contains(String word) {
return frequency(word) > 0;
}
/**
* #return a CharTrie Iterator over the Nodes in this CharTrie, starting at the root Node.
*/
public Iterator iterator() {
return new Iterator(root);
}
/**
* Node in the CharTrie.
* frequency-children entry
*/
private static final class Node {
/**
* the number of occurrences of the character that is associated to this Node,
* at certain position in the CharTrie
*/
private volatile int frequency = 0;
private static final AtomicIntegerFieldUpdater<Node> frequencyUpdater
= AtomicIntegerFieldUpdater.newUpdater(Node.class, "frequency");
/**
* the children of this Node
*/
private Map<Character, Node> children;
public Map<Character, Node> getChildren() {
if (children == null) {
children = new ConcurrentHashMap<>();
}
return children;
}
/**
* Atomically increments by one the current value of the frequency.
*
* #return the previous frequency
*/
private int getAndIncreaseFrequency() {
return frequencyUpdater.getAndIncrement(this);
}
}
/**
* Iterator over the Nodes in the CharTrie
*/
public static final class Iterator implements Cloneable {
/**
* Pointer to current Node
*/
private Node current;
private Iterator(Node current) {
this.current = current;
}
/**
* Returns true if the current Node contains the specified character in its children,
* then moves to the child Node.
* Otherwise, the current Node will not change.
*
* #param ch the character whose presence in the current Node's children is to be tested
* #return true if the current Node's children contains the specified character
*/
public boolean next(char ch) {
Node next = current.getChildren().get(ch);
if (next == null) {
return false;
}
current = next;
return true;
}
/**
* #return the current frequency of the current Node
*/
public int frequency() {
return current.frequency;
}
/**
* #return the newly created CharTrie Iterator, starting at the current Node of this Iterator
*/
#Override
#SuppressWarnings("CloneDoesntCallSuperClone")
public Iterator clone() {
return new Iterator(current);
}
}
}
and the WordGenerator :
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.function.BiConsumer;
/**
* #author FaNaJ
*/
public final class WordGenerator {
private WordGenerator() {
}
public static void generate(char[][] table, CharTrie.Iterator iterator, BiConsumer<String, Integer> action) {
final ForkJoinPool pool = ForkJoinPool.commonPool();
final VisitorContext ctx = new VisitorContext(table, action);
for (int y = 0; y < table.length; y++) {
for (int x = 0; x < table[y].length; x++) {
pool.invoke(new Visitor(new Point(x, y), null, "", iterator.clone(), ctx));
}
}
}
private static final class VisitorContext {
private final char[][] table;
private final BiConsumer<String, Integer> action;
private VisitorContext(char[][] table, BiConsumer<String, Integer> action) {
this.table = table;
this.action = action;
}
private boolean validate(Point point) {
Object c = null;
try {
c = table[point.getY()][point.getX()];
} catch (ArrayIndexOutOfBoundsException ignored) {
}
return c != null;
}
}
private static final class Visitor extends RecursiveAction {
private final Point current;
private final Point previous;
private final CharTrie.Iterator iterator;
private final VisitorContext ctx;
private String word;
private Visitor(Point current, Point previous, String word, CharTrie.Iterator iterator, VisitorContext ctx) {
this.current = current;
this.previous = previous;
this.word = word;
this.iterator = iterator;
this.ctx = ctx;
}
#Override
protected void compute() {
char nextChar = ctx.table[current.getY()][current.getX()];
if (iterator.next(nextChar)) {
word += nextChar;
int frequency = iterator.frequency();
if (frequency > 0) {
ctx.action.accept(word, frequency);
}
List<Visitor> tasks = new ArrayList<>();
for (Direction direction : Direction.values()) {
Point nextPoint = direction.move(current);
if (!nextPoint.equals(previous) && ctx.validate(nextPoint)) {
tasks.add(new Visitor(nextPoint, current, word, iterator.clone(), ctx));
}
}
invokeAll(tasks);
}
}
}
}
Note that I've used ForkJoinPool and RecursiveAction to speed up the search.
learn more :
https://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html
http://tutorials.jenkov.com/java-util-concurrent/java-fork-and-join-forkjoinpool.html
http://www.javaworld.com/article/2078440/enterprise-java/java-tip-when-to-use-forkjoinpool-vs-executorservice.html
the rest of classes :
PuzzleSolver
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.stream.Stream;
/**
* #author FaNaJ
*/
public final class PuzzleSolver {
private final CharTrie dictionary;
public enum OrderBy {FREQUENCY_IN_DICTIONARY, FREQUENCY_IN_PUZZLE}
public PuzzleSolver(CharTrie dictionary) {
this.dictionary = dictionary;
}
public CharTrie getDictionary() {
return dictionary;
}
public Stream<Word> solve(char[][] puzzle) {
return solve(puzzle, OrderBy.FREQUENCY_IN_DICTIONARY);
}
public Stream<Word> solve(char[][] puzzle, OrderBy orderBy) {
Stream<Word> stream = null;
switch (orderBy) {
case FREQUENCY_IN_DICTIONARY: {
final Map<String, Integer> words = new ConcurrentHashMap<>();
WordGenerator.generate(puzzle, dictionary.iterator(), words::put);
stream = words.entrySet().stream()
.map(e -> new Word(e.getKey(), e.getValue()));
break;
}
case FREQUENCY_IN_PUZZLE: {
final Map<String, AtomicInteger> words = new ConcurrentHashMap<>();
BiConsumer<String, Integer> action = (word, frequency) -> words.computeIfAbsent(word, s -> new AtomicInteger()).getAndIncrement();
WordGenerator.generate(puzzle, dictionary.iterator(), action);
stream = words.entrySet().stream()
.map(e -> new Word(e.getKey(), e.getValue().get()));
break;
}
}
return stream.sorted((a, b) -> b.compareTo(a));
}
}
http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/
Point
import java.util.Objects;
/**
* #author FaNaJ
*/
public final class Point {
private final int x;
private final int y;
public Point() {
this(0, 0);
}
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
#Override
public int hashCode() {
return x * 31 + y;
}
#Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Point that = (Point) obj;
return x == that.x && y == that.y;
}
#Override
public String toString() {
return "[" + x + ", " + y + ']';
}
}
Word
/**
* #author FaNaJ
*/
public final class Word implements Comparable<Word> {
private final String value;
private final int frequency;
public Word(String value, int frequency) {
this.value = value;
this.frequency = frequency;
}
public String getValue() {
return value;
}
public int getFrequency() {
return frequency;
}
#Override
public int hashCode() {
return value.hashCode() * 31 + frequency;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Word that = (Word) o;
return frequency == that.frequency && value.equals(that.value);
}
#Override
public String toString() {
return "{" +
"value='" + value + '\'' +
", frequency=" + frequency +
'}';
}
#Override
public int compareTo(Word o) {
return Integer.compare(frequency, o.frequency);
}
}
Direction
/**
* #author FaNaJ
*/
public enum Direction {
UP(0, 1), UP_RIGHT(1, 1), UP_LEFT(-1, 1),
RIGHT(1, 0), LEFT(-1, 0),
DOWN(0, -1), DOWN_RIGHT(1, -1), DOWN_LEFT(-1, -1);
private final int x, y;
Direction(int x, int y) {
this.x = x;
this.y = y;
}
public Point move(Point point) {
return new Point(point.getX() + x, point.getY() + y);
}
}
4. Test it
/**
* #author FaNaJ
*/
public class Test {
public static String[] DICTIONARY = {"OX", "CAT", "TOY", "AT", "DOG", "CATAPULT", "T", "AZOYZACZOTACXY"};
public static void main(String[] args) {
CharTrie trie = new CharTrie();
for (String word : DICTIONARY) {
trie.put(word);
}
PuzzleSolver solver = new PuzzleSolver(trie);
char[][] puzzle = {
{'C', 'A', 'T'},
{'X', 'Z', 'T'},
{'Y', 'O', 'T'}
};
solver.solve(puzzle, PuzzleSolver.OrderBy.FREQUENCY_IN_PUZZLE).forEach(System.out::println);
}
}
output :
{value='T', frequency=3}
{value='AT', frequency=2}
{value='CAT', frequency=2}
{value='TOY', frequency=2}
{value='OX', frequency=1}
{value='AZOYZACZOTACXY', frequency=1}
While I am studying Liang's book I am stuck at a point and I don't understand what is going on. The cause of error is the constructor of MyArrayList class. The author warns us about not calling super(object), but they didn't explain the reason. Now when I try and run the code the author is right - when we call super(object) I get an error. What is the cause of this error?
MyArrayList.java
public class MyArrayList<E> extends MyAbstractList<E> {
public static final int INITIAL_CAPACITY = 16;
private E[] data = (E[])new Object[INITIAL_CAPACITY];
/** Create a default list */
public MyArrayList() {
}
/** Create a list from an array of objects */
public MyArrayList(E[] objects) {
/*for (int i = 0; i < objects.length; i++)
add(objects[i]); // Warning: don't use super(objects)! */
super(objects); //!!! AUTHOR WARNS US ABOUT NOT INVOKING THIS LINE !!!
}
/** Add a new element at the specified index in this list */
public void add(int index, E e) {
ensureCapacity();
// Move the elements to the right after the specified index
for (int i = size - 1; i >= index; i--)
data[i + 1] = data[i];
// Insert new element to data[index]
data[index] = e;
// Increase size by 1
size++;
}
/** Create a new larger array, double the current size */
private void ensureCapacity() {
if (size >= data.length) {
E[] newData = (E[])(new Object[size * 2 + 1]);
System.arraycopy(data, 0, newData, 0, size);
data = newData;
}
}
/** Clear the list */
public void clear() {
data = (E[])new Object[INITIAL_CAPACITY];
size = 0;
}
/** Return true if this list contains the element */
public boolean contains(E e) {
for (int i = 0; i < size; i++)
if (e.equals(data[i])) return true;
return false;
}
/** Return the element from this list at the specified index */
public E get(int index) {
return data[index];
}
/** Return the index of the first matching element in this list.
* Return -1 if no match. */
public int indexOf(E e) {
for (int i = 0; i < size; i++)
if (e.equals(data[i])) return i;
return -1;
}
/** Return the index of the last matching element in this list
* Return -1 if no match. */
public int lastIndexOf(E e) {
for (int i = size - 1; i >= 0; i--)
if (e.equals(data[i])) return i;
return -1;
}
/** Remove the element at the specified position in this list
* Shift any subsequent elements to the left.
* Return the element that was removed from the list. */
public E remove(int index) {
E e = data[index];
// Shift data to the left
for (int j = index; j < size - 1; j++)
data[j] = data[j + 1];
data[size - 1] = null; // This element is now null
// Decrement size
size--;
return e;
}
/** Replace the element at the specified position in this list
* with the specified element. */
public E set(int index, E e) {
E old = data[index];
data[index] = e;
return old;
}
/** Override toString() to return elements in the list */
public String toString() {
StringBuilder result = new StringBuilder("[");
for (int i = 0; i < size; i++) {
result.append(data[i]);
if (i < size - 1) result.append(", ");
}
return result.toString() + "]";
}
/** Trims the capacity to current size */
public void trimToSize() {
if (size != data.length) { // If size == capacity, no need to trim
E[] newData = (E[])(new Object[size]);
System.arraycopy(data, 0, newData, 0, size);
data = newData;
}
}
}
MyList.java
public interface MyList<E> {
/** Add a new element at the end of this list */
public void add(E e);
/** Add a new element at the specified index in this list */
public void add(int index, E e);
/** Clear the list */
public void clear();
/** Return true if this list contains the element */
public boolean contains(E e);
/** Return the element from this list at the specified index */
public E get(int index);
/** Return the index of the first matching element in this list.
* Return -1 if no match. */
public int indexOf(E e);
/** Return true if this list contains no elements */
public boolean isEmpty();
/** Return the index of the last matching element in this list
* Return -1 if no match. */
public int lastIndexOf(E e);
/** Remove the first occurrence of the element o from this list.
* Shift any subsequent elements to the left.
* Return true if the element is removed. */
public boolean remove(E e);
/** Remove the element at the specified position in this list
* Shift any subsequent elements to the left.
* Return the element that was removed from the list. */
public E remove(int index);
/** Replace the element at the specified position in this list
* with the specified element and returns the new set. */
public Object set(int index, E e);
/** Return the number of elements in this list */
public int size();
}
MyAbstractList.java
public abstract class MyAbstractList<E> implements MyList<E> {
protected int size = 0; // The size of the list
/** Create a default list */
protected MyAbstractList() {
}
/** Create a list from an array of objects */
protected MyAbstractList(E[] objects) {
for (int i = 0; i < objects.length; i++)
add(objects[i]);
}
/** Add a new element at the end of this list */
public void add(E e) {
add(size, e);
}
/** Return true if this list contains no elements */
public boolean isEmpty() {
return size == 0;
}
/** Return the number of elements in this list */
public int size() {
return size;
}
/** Remove the first occurrence of the element o from this list.
* Shift any subsequent elements to the left.
* Return true if the element is removed. */
public boolean remove(E e) {
if (indexOf(e) >= 0) {
remove(indexOf(e));
return true;
}
else
return false;
}
}
TestMyArrayList.java
public class TestMyArrayList {
public static void main(String[] args)
{
String[] str = {"manisa","turkey","germany"};
MyList<String> list = new MyArrayList<String>(str);
list.add("America");
list.add(0,"Canada");
list.add(1,"England");
System.out.println(list);
}
}
Here is the error code :
Exception in thread "main" java.lang.NullPointerException
at MyArrayList.ensureCapacity(MyArrayList.java:36)
at MyArrayList.add(MyArrayList.java:21)
at MyAbstractList.add(MyAbstractList.java:16)
at MyAbstractList.<init>(MyAbstractList.java:11)
at MyArrayList.<init>(MyArrayList.java:16)
at TestMyArrayList.main(TestMyArrayList.java:8)
Lets simplify your code to the bare essentials:
public abstract class MyAbstractList<E> {
protected int size = 0; // The size of the list
protected MyAbstractList() {}
protected MyAbstractList(E[] objects) {
for (int i = 0; i < objects.length; i++)
add(objects[i]);
}
public class MyArrayList<E> extends MyAbstractList<E> {
public static final int INITIAL_CAPACITY = 16;
private E[] data = (E[])new Object[INITIAL_CAPACITY];
public MyArrayList(E[] objects) {
super(objects); // this call to super() executes before data is initialized
}
}
public static void main(String[] args) {
String[] str = {"manisa","turkey","germany"};
MyList<String> list = new MyArrayList<String>(str);
}
The important thing to understand is that the parent class' constructor is called before the child class is even initialized (which is why super() always has to be the first call in a constructor), meaning when MyAbstractList's constructor is running, data is still null.
Replacing the super() call with its contents means the for loop is executed while MyArrayList is initializing, after data has been properly set.
In essence, the problem is that MyAbstractList provides a constructor that calls methods that will be overridden by a child class, which is a serious anti-pattern. MyAbstractList should not provide an add-all style constructor.
For more, see Effective Java Item 17, which notes:
Constructors must not invoke overridable methods, directly or indirectly. If you violate this rule, program failure will result. The superclass constructor runs before the subclass constructor, so the overriding method in the subclass will get invoked before the subclass constructor has run. If the overriding method depends on any initialization performed by the subclass constructor, the method will not behave as expected.
The problem here is that the constructor in MyAbstractList is calling add before data has been initialized.
The data field is declared and initialized in the MyArrayList class. But the initialization doesn't occur until after the superclass initialization has finished, and the add calls are made during the superclass initialization ... when data is still null.
The general problem here is that it is dangerous for a constructor to call a method that could be overridden by a subclass. The override method is liable to be called before the subclass initialization has occurred.
In this case, add(E) could be overridden. Worse still, add(E) calls add(E, int) which definitely is overridden, because it is abstract in the superclass.
I have written my own priority_queue based on unsorted array, so adding new element works fast in O(1) but removing element with max priority(minimal value) works slow in O(N)
import java.util.*;
public class PriorityQueue<K extends Comparable> {
private int index;
private Comparable[] elements;
public Object[] getElements() {
return elements;
}
public PriorityQueue(int capacity) {
if (capacity < 0)
capacity = 10;
elements = new Comparable[capacity];
}
public PriorityQueue() {
this(10);
}
public boolean isEmpty() {
return index == 0;
}
public int size() {
return index;
}
private void resize() {
elements = Arrays.copyOf(elements, elements.length * 2);
}
public void add(K element) {
if (index == elements.length)
resize();
elements[index++] = element;
}
public Comparable remove() {
if (isEmpty())
throw new PriorityQueueIsEmptyException("Queue is empty!");
int priorityIndex = 0;
for (int i = 1; i < index; i++) {
if (elements[i].compareTo(elements[priorityIndex]) < 0)
priorityIndex = i;
}
Comparable result = elements[priorityIndex];
index--;
elements[priorityIndex] = elements[index];
return result;
}
public Comparable<K> poll() {
if (isEmpty())
return null;
return remove();
}
public Comparable element() {
if (isEmpty())
throw new PriorityQueueIsEmptyException("Queue is empty!");
int priorityIndex = 0;
for (int i = 1; i < index; i++) {
if (elements[i].compareTo(elements[priorityIndex]) < 0)
priorityIndex = i;
}
return elements[priorityIndex];
}
public Comparable peek() {
if (isEmpty())
return null;
return element();
}
public Iterator iterator() {
return new QueueIterator();
}
public void print() {
for (int i = 0; i < index; i++) {
System.out.print(elements[i] + " --> ");
}
System.out.println();
}
private class QueueIterator implements Iterator {
// we keep list of indexes of elements that have been taken allready by method next()
// we keep it in order not to check elements with such indexes when we are founding new min element
// sorry for my eng
private List<Integer> usedIndexes;
private Comparable next;
public QueueIterator() {
usedIndexes = new ArrayList<Integer>();
}
private Comparable min(Comparable[] elements, int from, int to, List<Integer> usedIndexes) {
// trick to assign min value
// we cannot start from the first element cause he might be minimal allready
int startIndex = from;
for (int i = from; i <= to; i++) {
if (!usedIndexes.contains(i)) {
startIndex = i;
break;
}
}
Comparable min = elements[startIndex];
int minIndex = startIndex;
for (int i = from; i <= to; i++) {
if (!usedIndexes.contains(i) && elements[i].compareTo(min) < 0) {
min = elements[i];
minIndex = i;
}
}
usedIndexes.add(minIndex);
return min;
}
#Override
public boolean hasNext() {
return usedIndexes.size() == index;
}
#Override
public Comparable next() {
if (isEmpty())
throw new NoSuchElementException();
next = min(elements, 0, index - 1, usedIndexes);
return next;
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}
public class PriorityQueueIsEmptyException extends RuntimeException {
PriorityQueueIsEmptyException() {
}
PriorityQueueIsEmptyException(String message) {
super(message);
}
}
My questions are:
had I made iterator right?
it seems to me that its not good that method next(), which works in O(N * N), am I right?
is there any way to do iterator better?
I want to initialize an Item Array but can't figure it out.
Here is my code.
public class HashTable<Item> {
private int m; // hash table size
private Item[] T; // hash table
HashTable(int M)
{
m = M;
T = new Item[M];
for(int i=0;i<M;i++){
Item T[i] = null;
}
}
...
...
SOLUTION
T = (Item[])new Object[M];
I think what you need is something like:
for(int i=0;i<M;i++){
T[i] = new Item(); // call some constructor here
}
You have
Item T[i] = ...
in your loop, while it should be just
T[i] = ...
So try these hints.
Also do this:
T = (Item[])new Object[M];
as Kumar suggested in his reply.
The thing is that Item is not really a type here. You need
to read how generics are actually compiled into bytecode,
and you will see what happens under the hood.
You are trying to create the array of Generic type,Please look at this post.
How to create a generic array in Java?
Assuming you created the class item you could call it like this:
public class HashTable
{
private int tableSize; // hash table size
private Item[] table; // hash table
public static void main(String[] args)
{
// where 10 is the number of nodes
Item[] myTable = createHashTable(10);
}
private static Item[] createHashTable(int size)
{
Item[] table = new Item[size];
for(int i = 0; i < table.length; i++)
{
table[i] = new Item(i);
}
}
}
However if you want to see an example of a full HashTable implementation:
/*
* HashTable.java
*
*
*/
/**
* A class that implements a hash table that employs open addressing
* using either linear probing, quadratic probing, or double hashing.
*/
public class HashTable {
/* Private inner class for an entry in the hash table */
private class Entry {
private String key;
private LLList valueList; // all of the values with this key
private boolean hasBeenRemoved; // has this entry been removed?
private Entry(String key, int value) {
this.key = key;
valueList = new LLList();
valueList.addItem(value, 0);
hasBeenRemoved = false;
}
}
// parameters for the second hash function -- see h2() below
private static final int H2_MIN = 5;
private static final int H2_DIVISOR = 11;
// possible types of probing
public static final int LINEAR = 0;
public static final int QUADRATIC = 1;
public static final int DOUBLE_HASHING = 2;
public static final int NUM_PROBE_TYPES = 3;
private Entry[] table; // the hash table itself
private int probeType = LINEAR; // the type of probing
// keeps track of how many times we perform a probe of a given length
private int[] probeLengthCount;
public HashTable(int size, int probeType) {
if (probeType >= 0 && probeType < NUM_PROBE_TYPES)
this.probeType = probeType;
else
throw new IllegalArgumentException("invalid probeType: " +
probeType);
table = new Entry[size];
probeLengthCount = new int[size + 1];
for (int i = 0; i <= size; i++)
probeLengthCount[i] = 0;
}
public HashTable(int size) {
// Call the other constructor to do the work.
this(size, LINEAR);
}
/* first hash function */
private int h1(String key) {
int h1 = key.hashCode() % table.length;
if (h1 < 0)
h1 += table.length;
return h1;
}
/* second hash function */
private int h2(String key) {
int h2 = key.hashCode() % H2_DIVISOR;
if (h2 < 0)
h2 += H2_DIVISOR;
h2 += H2_MIN;
return h2;
}
/*
* probeIncrement - returns the amount by which the current index
* should be incremented to obtain the nth element in the probe
* sequence
*/
private int probeIncrement(int n, int h2) {
if (n <= 0)
return 0;
switch (probeType) {
case LINEAR:
return 1;
case QUADRATIC:
return (2*n - 1);
case DOUBLE_HASHING:
default:
return h2;
}
}
/*
* probe - attempt to find a slot in the hash table for the specified key.
*
* If key is currently in the table, it returns the index of the entry.
* If key isn't in the table, it returns the index of the first empty cell
* in the table.
* If overflow occurs, it returns -1.
*/
private int probe(String key) {
int i = h1(key); // first hash function
int h2 = h2(key); // second hash function
int positionsChecked = 1;
// keep probing until we get an empty position or a match
while (table[i] != null && !key.equals(table[i].key)) {
if (positionsChecked == table.length) {
probeLengthCount[positionsChecked]++;
return -1;
}
i = (i + probeIncrement(positionsChecked, h2)) % table.length;
positionsChecked++;
}
probeLengthCount[positionsChecked]++;
return i;
}
/**
* insert - insert the specified (key, value) pair in the hash table
*/
public void insert(String key, int value) {
if (key == null)
throw new IllegalArgumentException("key must be non-null");
int i = h1(key);
int h2 = h2(key);
int positionsChecked = 1;
int firstRemoved = -1;
while (table[i] != null && !key.equals(table[i].key)) {
if (table[i].hasBeenRemoved && firstRemoved == -1)
firstRemoved = i;
if (positionsChecked == table.length)
break;
i = (i + probeIncrement(positionsChecked, h2)) % table.length;
positionsChecked++;
}
probeLengthCount[positionsChecked]++;
if (table[i] != null && key.equals(table[i].key))
table[i].valueList.addItem(value, 0);
else if (firstRemoved != -1)
table[firstRemoved] = new Entry(key, value);
else if (table[i] == null)
table[i] = new Entry(key, value);
else
throw new RuntimeException("overflow occurred");
}
/**
* search - search for the specified key, and return the
* associated list of values, or null if the key is not in the
* table
*/
public LLList search(String key) {
if (key == null)
throw new IllegalArgumentException("key must be non-null");
int i = probe(key);
if (i == -1 || table[i] == null)
return null;
else
return table[i].valueList;
}
/**
* remove - remove from the table the entry for the specified key
*/
public void remove(String key) {
if (key == null)
throw new IllegalArgumentException("key must be non-null");
int i = probe(key);
if (i == -1 || table[i] == null)
return;
table[i].key = null;
table[i].valueList = null;
table[i].hasBeenRemoved = true;
}
/**
* printStats - print the statistics for the table -- i.e., the
* number of keys and items, and stats for the number of times
* that probes of different lengths were performed
*/
public void printStats() {
int numProbes = 0;
int probeLengthSum = 0;
int numKeys = 0;
for (int i = 0; i < table.length; i++) {
if (table[i] != null && !table[i].hasBeenRemoved)
numKeys++;
}
System.out.println("\n" + numKeys + " keys");
System.out.println("probe-length stats:");
System.out.println("length\tcount");
for (int i = 1; i <= table.length; i++) {
if (probeLengthCount[i] != 0)
System.out.println(i + "\t" + probeLengthCount[i]);
numProbes += probeLengthCount[i];
probeLengthSum += (probeLengthCount[i] * i);
}
System.out.println("average probe length = " +
(double)probeLengthSum / numProbes);
}
}
Here is the second file for a Linked-Linked-List
/*
* LLList.java
*
*
*/
import java.util.*;
/**
* A class that implements our simple List interface using a linked list.
* The linked list includes a dummy head node that allows us to avoid
* special cases for insertion and deletion at the front of the list.
*/
public class LLList implements List {
// Inner class for a node. We use an inner class so that the LLList
// methods can access the instance variables of the nodes.
private class Node {
private Object item;
private Node next;
private Node(Object i, Node n) {
item = i;
next = n;
}
}
private Node head; // dummy head node
private int length; // # of items in the list
/**
* Constructs a LLList object for a list that is initially empty.
*/
public LLList() {
head = new Node(null, null);
length = 0;
}
/*
* getNode - private helper method that returns a reference to the
* ith node in the linked list. It assumes that the value of the
* parameter is valid.
*
* If i == -1, it returns a reference to the dummy head node.
*/
private Node getNode(int i) {
Node trav = head;
int travIndex = -1;
while (travIndex < i) {
travIndex++;
trav = trav.next;
}
return trav;
}
/** getItem - returns the item at position i in the list */
public Object getItem(int i) {
if (i < 0 || i >= length)
throw new IndexOutOfBoundsException();
Node n = getNode(i);
return n.item;
}
/**
* addItem - adds the specified item at position i in the list,
* shifting the items that are currently in positions i, i+1, i+2,
* etc. to the right by one. Always returns true, because the list
* is never full.
*
* We don't need a special case for insertion at the front of the
* list (i == 0), because getNode(0 - 1) will return the dummy
* head node, and the rest of insertion can proceed as usual.
*/
public boolean addItem(Object item, int i) {
if (i < 0 || i > length)
throw new IndexOutOfBoundsException();
Node newNode = new Node(item, null);
Node prevNode = getNode(i - 1);
newNode.next = prevNode.next;
prevNode.next = newNode;
length++;
return true;
}
/**
* removeItem - removes the item at position i in the list,
* shifting the items that are currently in positions i+1, i+2,
* etc. to the left by one. Returns a reference to the removed
* object.
*
* Here again, we don't need a special case for i == 0 (see the
* note accompanying addItem above).
*/
public Object removeItem(int i) {
if (i < 0 || i >= length)
throw new IndexOutOfBoundsException();
Node prevNode = getNode(i - 1);
Object removed = prevNode.next.item;
prevNode.next = prevNode.next.next;
length--;
return removed;
}
/** length - returns the number of items in the list */
public int length() {
return length;
}
/**
* isFull - always returns false, because the linked list can
* grow indefinitely and thus the list is never full.
*/
public boolean isFull() {
return false;
}
/**
* toString - converts the list into a String of the form
* [ item0 item1 ... ]
*/
public String toString() {
String str = "[ ";
Node trav = head.next; // skip over the dummy head node
while (trav != null) {
str += (trav.item + " ");
trav = trav.next;
}
str += "]";
return str;
}
/**
* iterator - returns an iterator for this list
*/
public ListIterator iterator() {
return new LLListIterator();
}
/*
*** private inner class for an iterator over an LLList ***
*/
private class LLListIterator implements ListIterator {
private Node nextNode; // the next node to visit
private Node lastVisitedNode; // the most recently visited node
public LLListIterator() {
nextNode = head.next;
lastVisitedNode = null;
}
/**
* hasNext - does the iterator have additional items to visit?
*/
public boolean hasNext() {
return (nextNode != null);
}
/**
* next - returns a reference to the next Object in the iteration
*/
public Object next() {
if (nextNode == null)
throw new NoSuchElementException();
Object item = nextNode.item;
lastVisitedNode = nextNode;
nextNode = nextNode.next;
return item;
}
}
}