I am implementing Fibonacci Heap to improve on my Dijkstra's shortest path algorithm. My insert method works fine, and the next one I needed to do is extract-min. I am following CLRS. Please note some attributes mentioned in the book aren't in my implementation yet, as they are not needed for the functions so far, but I will add them later.
private static class FibonacciHeap {
/**
* Implementation of the node used in
* fibonacci heap. The nodes are stored
* as a circular doubly-linked list, making
* delete and insert operations easy, as
* well as being able to iterate through
* without being forced to keep track of the
* head
*/
private class Node {
/**
* The vertex this node is storing
*/
Vertex val;
/**
* Key used to know the order of vertices
*/
int key;
/**
* The left and right sibling in the list
*/
Node left, right;
/**
* Pointer to one of the child's
*/
Node child;
/**
* The amount of children this node has
*/
int degree;
/**
* Constructs a node with a value and key
*
* #param val the value of this node
* #param key the key of this node
*/
public Node(Vertex val, int key) {
this.val = val;
this.key = key;
}
/**
* Inserts a new node into this node's list.
* Inserts it to the left of this node, while
* maintaining the fact that it's circular
*
* #param newNode The new node to be inserted
*/
public void insert(Node newNode) {
newNode.left = left;
left.right = newNode;
newNode.right = this;
left = newNode;
if(newNode.key < min.key) {
min = newNode;
}
size++;
}
/**
* Removes this node from it's list
*/
public void remove() {
right.left = left;
left.right = right;
}
/**
* Inserts a new child into this nodes
* child list
*
* #param child The new node to be added as a child
*/
public void link(Node child) {
child.remove();
if(this.child == null) {
this.child = child;
} else {
this.child.insert(child);
}
degree ++;
}
/**
* Used for debugging. Will be removed after
* all operations work fine
*
* #return A string representation of this node
*/
#Override
public String toString() {
Node dummy = right;
StringBuilder sb = new StringBuilder();
sb.append(key).append(" -> (");
sb.append(dummy.child);
sb.append(") ");
while(dummy != this) {
sb.append(dummy.key).append(" -> (");
sb.append(dummy.child);
sb.append(") ");
dummy = dummy.right;
}
return sb.toString();
}
}
/**
* Pointer to the node with the smallest key
*/
private Node min;
/**
* Stores the number of nodes in the heap
*/
private int size;
/**
* Creates an empty Fibonacci Heap
*/
public FibonacciHeap() { }
/**
* Gets and returns the key with the
* smallest value
*
* #return the key with the smallest value
*/
public int getMin() {
if(min == null) {
throw new NoSuchElementException("Empty Fibonacci Heap");
}
return min.key;
}
/**
* Inserts a vertex along with a key. The
* key is the one used to measure whether
* this vertex is lesser than another
*
* #param vertex vertex to be added
* #param key key of the vertex
*/
public void insert(Vertex vertex, int key) {
if(min == null) {
min = new Node(vertex, key);
min.left = min;
min.right = min;
size = 1;
} else {
min.insert(new Node(vertex, key));
}
}
/**
* Removes the node with the smallest key from
* the heap, and updates the minimum node if needed
*
* #return The node with the smallest key prior to this method call
*/
public Vertex extractMin() {
if(isEmpty()) {
throw new NoSuchElementException("Empty Fibonacci Heap");
}
Vertex toReturn;
if(min == null) {
toReturn = null;
} else {
toReturn = min.val;
if(min.right == min) {
min = null;
} else {
min.remove();
min = min.right;
consolidate();
}
}
return toReturn;
}
/**
* Consolidates the heap. Consolidation is the process
* making every node in the root list have it's own
* unique degree. That is, every node in the top most
* layer has a unique amount of children
*/
private void consolidate() {
Node[] degrees = new Node[size];
degrees[min.degree] = min;
Node tempMin, dummy = (tempMin = min).right;
while(dummy != tempMin) {
if(dummy.key < min.key) {
min = dummy;
}
while(degrees[dummy.degree] != null) {
Node other = degrees[dummy.degree];
if(other.key < dummy.key) {
Node temp = dummy;
dummy = other;
other = temp;
}
dummy.link(other);
degrees[dummy.degree - 1] = null;
}
degrees[dummy.degree] = dummy;
}
}
/**
* Returns true if and only if the
* heap is empty
*
* #return if the heap is empty
*/
public boolean isEmpty() {
return min == null;
}
/**
* A string representation of this
* heap. Format of string is:
* node1 -> (node1.child.toString()) node2 -> (node2.child.toString()) ... noden -> (noden.child.toString())
* The string representation of the
* heap is the string representation of
* the minimum node
*
* #return A string representation of this heap
*/
#Override
public String toString() {
return min.toString();
}
}
This is the stack trace that it gives:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 10
at GraphTheory.ShortestPathAlgorithms.DijkstraShortestPath$FibonacciHeap.consolidate(DijkstraShortestPath.java:362)
at GraphTheory.ShortestPathAlgorithms.DijkstraShortestPath$FibonacciHeap.extractMin(DijkstraShortestPath.java:338)
at GraphTheory.ShortestPathAlgorithms.DijkstraShortestPath.main(DijkstraShortestPath.java:104)
The main error is given in the conditional statement of the inner while loop in the consolidate function. I also commented the line in the code. What is going wrong? My main testing method insert 10 random numbers from 1 - 10, and then extracts the minimum until it's empty. The error occurs the first time extract-min is called.
public static void main(String[] args) {
FibonacciHeap f = new FibonacciHeap();
StringBuilder sb = new StringBuilder();
for(int i = 0; i < 10; i ++) {
f.insert(new Vertex(i), (int) (Math.random() * 10));
}
while(!f.isEmpty()) {
System.out.println(f.extractMin());
}
}
Can't pinpoint the exact bug. But, I can tell you from experience that you should not find the minimum while consolidating. You consolidate and then you find the new minimum. You might get into trouble when you have multiple nodes with the same key and the one pointed to by min doesn't end up in the root list.
Also, while testing, don't use a random function. Create an array of arbitrary numbers and insert elements from the array into the heap.
I also don't understand how your implementation handles there being only one heap ordered tree in the Fib heap. What happens when you do an extract-min then?
You can find my Python implementation here if you need it.
Related
I've been trying to program a LinkedList implementation of a Stack and of a Queue. Whenever I run them however, I get an error letting me know that the list is empty when I try and pop/dequeue anything. The thing is, if I call .toString() on the list, even RIGHT before the pop/dequeue command, I can see that they're not. I can't myself see anything wrong with my pop/dequeue implementation, but perhaps you fine folks can help me out.
LinkedList.java
package jsjf;
import jsjf.exceptions.*;
import java.util.*;
/**
* LinkedList represents a linked implementation of a list.
*
* #author Java Foundations
* #version 4.0
*/
public class LinkedList<T> implements ListADT<T>, Iterable<T>
{
protected int count;
protected LinearNode<T> head, tail;
protected int modCount;
/**
* Creates an empty list.
*/
public LinkedList()
{
count = 0;
head = tail = null;
modCount = 0;
}
/**
* Adds a new element to the end of the list.
*
* #param element the element to add.
*/
public void add(T element) {
// If the list is empty...
if(this.tail == null){
// Creates a new node for the new element.
LinearNode<T> newElement = new LinearNode(element);
// Assigns the new node to be the head and the tail.
this.tail = this.head = newElement;
}
// Otherwise...
else {
// Temporary caches the old tail.
LinearNode<T> temp = this.tail;
// Creates a new node for the new element.
LinearNode<T> newElement = new LinearNode(element);
// Assigns the new node to follow the old tail.
temp.setNext(newElement);
// Assigns the old tail to precede the new node.
newElement.setPrevious(temp);
// Assigns the new node to be the tail.
this.tail = newElement;
}
}
/**
* Adds a new element at a specific index, bumping the current element at
* that index to the next index.
*
* #param index the index to add to.
* #param element the element to add.
*/
public void add(int index, T element) {
// Find the node at the index requested.
LinearNode<T> desiredIndex = this.head;
for(int i = 1; i <= index; i++){
desiredIndex = desiredIndex.getNext();
}
// Hold the previous element of the old element.
LinearNode<T> prev = desiredIndex.getPrevious();
// Create a new node for the new element.
LinearNode<T> newElement = new LinearNode(element);
// Assign prev to precede the new element.
newElement.setPrevious(prev);
// Assign the old element to follow the new element.
newElement.setNext(desiredIndex);
// Assign the new element to precede the old element.
desiredIndex.setPrevious(newElement);
}
/**
* Returns an element from a specific index, without removing it.
*
* #param index the index to check.
* #return the element at that index.
*/
public T get(int index) {
// Find the node at the index requested.
LinearNode<T> desiredIndex = this.head;
for(int i = 1; i <= index; i++){
desiredIndex = desiredIndex.getNext();
}
// Return that element.
return desiredIndex.getElement();
}
/** Removes the first element in this list and returns a reference
* to it. Throws an EmptyCollectionException if the list is empty.
*
* #return a reference to the first element of this list
* #throws EmptyCollectionException if the list is empty
*/
public T removeFirst() throws EmptyCollectionException
{
if (isEmpty())
throw new EmptyCollectionException("list");
T result = head.getElement();
head = head.getNext();
count--;
if(isEmpty())
tail = null;
modCount++;
return result;
}
/**
* Removes the last element in this list and returns a reference
* to it. Throws an EmptyCollectionException if the list is empty.
*
* #return the last element in this list
* #throws EmptyCollectionException if the list is empty
*/
public T removeLast() throws EmptyCollectionException
{
if (isEmpty())
throw new EmptyCollectionException("list");
T result = tail.getElement();
tail = tail.getPrevious();
count--;
if(isEmpty())
tail = null;
modCount++;
return result;
}
/**
* Removes the first instance of the specified element from this
* list and returns a reference to it. Throws an EmptyCollectionException
* if the list is empty. Throws a ElementNotFoundException if the
* specified element is not found in the list.
*
* #param targetElement the element to be removed from the list
* #return a reference to the removed element
* #throws EmptyCollectionException if the list is empty
* #throws ElementNotFoundException if the target element is not found
*/
public T remove(T targetElement) throws EmptyCollectionException,
ElementNotFoundException
{
if (isEmpty())
throw new EmptyCollectionException("LinkedList");
boolean found = false;
LinearNode<T> previous = null;
LinearNode<T> current = head;
while (current != null && !found)
if (targetElement.equals(current.getElement()))
found = true;
else
{
previous = current;
current = current.getNext();
}
if (!found)
throw new ElementNotFoundException("LinkedList");
if (size() == 1) // only one element in the list
head = tail = null;
else if (current.equals(head)) // target is at the head
head = current.getNext();
else if (current.equals(tail)) // target is at the tail
{
tail = previous;
tail.setNext(null);
}
else // target is in the middle
previous.setNext(current.getNext());
count--;
modCount++;
return current.getElement();
}
/**
* Changes the element at a specific index.
*
* #param index the index to change.
* #param element the element to change to.
*/
public void set(int index, T element) {
// Find the node at the index requested.
LinearNode<T> desiredIndex = this.head;
for(int i = 1; i <= index; i++){
desiredIndex = desiredIndex.getNext();
}
// Change the element at that index.
desiredIndex.setElement(element);
}
/**
* Returns the first element in this list without removing it.
*
* #return the first element in this list
* #throws EmptyCollectionException if the list is empty
*/
public T first() throws EmptyCollectionException
{
if (isEmpty())
throw new EmptyCollectionException("list");
T result = head.getElement();
return result;
}
/**
* Returns the last element in this list without removing it.
*
* #return the last element in this list
* #throws EmptyCollectionException if the list is empty
*/
public T last() throws EmptyCollectionException
{
if (isEmpty())
throw new EmptyCollectionException("list");
T result = tail.getElement();
return result;
}
/**
* Returns true if the specified element is found in this list and
* false otherwise. Throws an EmptyCollectionException if the list
* is empty.
*
* #param targetElement the element that is sought in the list
* #return true if the element is found in this list
* #throws EmptyCollectionException if the list is empty
*/
public boolean contains(T targetElement) throws
EmptyCollectionException
{
if(isEmpty())
throw new EmptyCollectionException("list");
boolean found = false;
LinearNode<T> previous = null;
LinearNode<T> current = head;
while (current != null && !found)
if (targetElement.equals(current.getElement()))
found = true;
else
{
previous = current;
current = current.getNext();
}
if (!found)
throw new ElementNotFoundException("LinkedList");
return found;
}
/**
* Returns true if this list is empty and false otherwise.
*
* #return true if the list is empty, false otherwise
*/
public boolean isEmpty()
{
return (count == 0);
}
/**
* Returns the number of elements in this list.
*
* #return the number of elements in the list
*/
public int size()
{
return count;
}
/**
* Returns a string representation of this list.
*
* #return a string representation of the list
*/
public String toString()
{
String result = "";
LinearNode current = head;
while (current != null)
{
result = result + current.getElement() + "\n";
current = current.getNext();
}
return result;
}
/**
* Returns an iterator for the elements in this list.
*
* #return an iterator over the elements of the list
*/
public Iterator<T> iterator()
{
return new LinkedListIterator();
}
/**
* LinkedIterator represents an iterator for a linked list of linear nodes.
*/
private class LinkedListIterator implements Iterator<T>
{
private int iteratorModCount; // the number of elements in the collection
private LinearNode<T> current; // the current position
/**
* Sets up this iterator using the specified items.
*
* #param collection the collection the iterator will move over
* #param size the integer size of the collection
*/
public LinkedListIterator()
{
current = head;
iteratorModCount = modCount;
}
/**
* Returns true if this iterator has at least one more element
* to deliver in the iteration.
*
* #return true if this iterator has at least one more element to deliver
* in the iteration
* #throws ConcurrentModificationException if the collection has changed
* while the iterator is in use
*/
public boolean hasNext() throws ConcurrentModificationException
{
if (iteratorModCount != modCount)
throw new ConcurrentModificationException();
return (current != null);
}
/**
* Returns the next element in the iteration. If there are no
* more elements in this iteration, a NoSuchElementException is
* thrown.
*
* #return the next element in the iteration
* #throws NoSuchElementException if the iterator is empty
*/
public T next() throws ConcurrentModificationException
{
if (!hasNext())
throw new NoSuchElementException();
T result = current.getElement();
current = current.getNext();
return result;
}
/**
* The remove operation is not supported.
*
* #throws UnsupportedOperationException if the remove operation is called
*/
public void remove() throws UnsupportedOperationException
{
throw new UnsupportedOperationException();
}
}
}
LinkedListQueue.java
package jsjf;
public class LinkedListQueue<T> implements QueueADT<T> {
LinkedList queue = new LinkedList();
/**
* Adds the specified element to the back of this queue.
*
* #param element generic element to be pushed onto queue.
*/
public void enqueue(T element) {
queue.add(element);
}
/**
* Removes the element from the front of the queue and returns it.
*
* #return the element from the front of the queue.
*/
public T dequeue() {
return (T) queue.removeFirst();
}
/**
* Returns the front element, without removing it.
*
* #return the element at the front of the queue.
*/
public T first() {
return (T) queue.first();
}
/**
* Returns true if the queue is empty.
*
* #return the boolean value of this queue being empty.
*/
public boolean isEmpty() {
if(queue.isEmpty())
return true;
return false;
}
/**
* Returns the number of elements contained in the queue.
*
* #return the number of elements contained in the queue.
*/
public int size() {
return queue.size();
}
/**
* Returns the queue as a string.
*
* #return the queue as a string.
*/
public String toString() {
return queue.toString();
}
}
LinkedListStack.java
package jsjf;
public class LinkedListStack<T> implements StackADT<T> {
LinkedList stack = new LinkedList();
/**
* Adds the specified element to the top of this stack.
*
* #param element generic element to be pushed onto stack.
*/
public void push(T element) {
stack.add(element);
}
/**
* Removes the element from the top of the stack and returns it.
*
* #return the element from the top of the stack.
*/
public T pop() {
return (T) stack.removeLast();
}
/**
* Returns the top element, without removing it.
*
* #return the element at the top of the stack.
*/
public T peek() {
return (T) stack.last();
}
/**
* Returns true if the stack is empty.
*
* #return the boolean value of this stack being empty.
*/
public boolean isEmpty() {
if(stack.isEmpty())
return true;
return false;
}
/**
* Returns the number of elements contained in the stack.
*
* #return the number of elements contained in the stack.
*/
public int size() {
return stack.size();
}
/**
* Returns the stack as a string.
*
* #return the stack as a string.
*/
public String toString() {
return stack.toString();
}
}
Driver.java
package jsjf;
public class Driver {
public static void main(String[] args) {
// Instantiate the array based structures.
ArrayListQueue arrayQueue = new ArrayListQueue();
ArrayListStack arrayStack = new ArrayListStack();
// Instantiate the link based structures.
LinkedListQueue linkedQueue = new LinkedListQueue();
LinkedListStack linkedStack = new LinkedListStack();
// An integer to hold reference to a data piece to be pushed to the structures.
int data;
// Randomly generate a piece of data, and pass it to the structures.
for(int i = 0; i < 25; i++){
data = (int)(Math.random() * 50);
arrayQueue.enqueue(data);
arrayStack.push(data);
linkedQueue.enqueue(data);
linkedStack.push(data);
}
System.out.print("Array Queue: ");
for(int i = 0; i < 25; i++){
System.out.print(arrayQueue.dequeue() + " ");
}
System.out.println();
System.out.print("Array Stack: ");
for(int i = 0; i < 25; i++){
System.out.print(arrayStack.pop() + " ");
}
System.out.println();
System.out.print("\n\nLinked Stack as string: " + linkedStack.toString() + "\n\n");
System.out.print("Linked Stack: ");
for(int i = 0; i < 25; i++){
System.out.print(linkedStack.pop() + " ");
}
System.out.println();
System.out.print("Linked Queue: " + linkedQueue.toString());
System.out.print("Linked Queue: ");
for(int i = 0; i < 25; i++){
System.out.print(linkedQueue.dequeue() + " ");
}
System.out.println();
}
}
When I run Driver.java, I get the following output.
Array Queue: 45 12 25 40 31 32 14 16 14 26 3 25 22 26 29 6 13 12 30 10 46 10 11 3 11
Array Stack: 11 3 11 10 46 10 30 12 13 6 29 26 22 25 3 26 14 16 14 32 31 40 25 12 45
Linked Stack as string: 45
12
25
40
31
32
14
16
14
26
3
25
22
26
29
6
13
12
30
10
46
10
11
3
11
Linked Stack: Exception in thread "main" jsjf.exceptions.EmptyCollectionException: The list is empty.
at jsjf.LinkedList.removeLast(LinkedList.java:135)
at jsjf.LinkedListStack.pop(LinkedListStack.java:24)
at jsjf.Driver.main(Driver.java:46)
Looks like you don't increment count in your add methods for the linked list, but are using count to determine if its empty or not.
What i need to do in this assignment, is to implement the given methods from the interface. If you could check and give me some feedback on what i've delivered so far, would be very much appreciated.
I am still missing one method unfortunately, public T getNext8thElementOf(int pos). Does anyone has an idea on how to implement it?
/**
* A simple list interface
* #param <T> The type of list element
*/
public interface ISpeedList<T> {
/**
* Returns the current number of elements in the list
*
* #return Current number of elements in the list
*/
public int size();
/**
* Inserts an element at the beginning of the list
*
* #param item Item to be inserted
*/
public void prepend(T item);
/**
* Returns the element at the specified position in the list
*
* #param pos The position of the element in the list starting from 0
*
* #return The specified element in the list
*
* #throws IndexOutOfBoundsException If the requested element is out of
* range
*/
public T getElementAt(int pos);
/**
* Returns the next 8th element of the specified element in the list
*
* #param pos The position of the specified element in the list starting
* from 0
*
* #return The next 8th element of the specified element
*
* #throws IndexOutOfBoundsException If the requested element is out of
* range
*/
public T getNext8thElementOf(int pos);
}
public class SpeedList<T> implements ISpeedList<T> {
/**
* Doubly-linked node class, completely private to the List class,
* as clients don't care about the implementation of the list.
*/
private class Node {
T item;
Node next;
Node previous;
Node(T item, Node next, Node previous) {
this.item = item;
this.next = next;
this.previous = previous;
}
}
/**
* The list itself maintains only a reference to its "header" node.
* The header is a node that does not store any data. Its 'next'
* field points to the first item in the list and its 'previous'
* field points to the last item. This makes all insertions and
* deletions uniform, even at the beginning and the end of the list!
*/
private Node header = new Node(null, null, null);
/**
* The number of items in the list, stored to make size() O(1).
*/
private int size = 0;
/**
* Returns the number of items in the list.
*/
#Override
public int size() {
return size;
}
/**
* Inserts <code>item</code> as the new first item.
*/
#Override
public void prepend(T item) {
addBefore(item, header.next);
}
/**
* Returns the item at the given index position.
*
* #throws IndexOutOfBoundsException
* if index not in [0,size).
*/
#Override
public T getElementAt(int pos) {
return nodeAt(pos).item;
}
#Override
public T getNext8thElementOf(int pos) {
// TODO Auto-generated method stub
return null;
}
//
// PRIVATE HELPER METHODS
//
private Node nodeAt(int pos) {
if (pos < 0 || pos >= size) {
throw new IndexOutOfBoundsException(pos + " for size " + size);
}
Node n = header;
for (int i = 0; i <= pos; i++) {
n = n.next;
}
return n;
}
private void addBefore(T o, Node n) {
Node newNode = new Node(o, n, n.previous);
newNode.previous.next = newNode;
newNode.next.previous = newNode;
size++;
}
}
Is that what you want?
#Override
public T getNext8thElementOf(int pos) {
int eight = 8;
Node nodo = this.nodeAt(pos);
while(eight > 0) {
eight--;
nodo = nodo.next;
}
return nodo.item;
}
I have a project issue where I need to check if a linked list is a palindrome, the same forward as it is backward. I was given a class titled a Node class that contains specific information that I am not allowed to change so I must use what I have in that class and cant write more there to help me. My problem is I can get through the list, but I don't know how to go backwards through and compare values.
Disclaimer: I don't want a complete answer just tips/ideas!
Here is the class I can't change and have to work with:
class Node {
/**
* The value stored in the node.
*/
public Character value;
/**
* A pointer to the next node in
* the list.
*/
public Node next;
/**
* A pointer to the previous node
* in the list. (Note: having this
* pointer makes this a "doubly linked"
* list.
*/
public Node prev;
/**
* A constructor to set up a
* node with a value.
*
* #param value the value to put in the node
*/
public Node(Character value) {
this.value = value;
}
/**
* A constructor to set up a
* node with a value and a pointer
* to the previous node (so I can
* append items easily in my test
* code).
*
* #param value the value to put in the node
* #param prev the previous node in the list
*/
public Node(Character value, Node prev) {
this.value = value;
this.prev = prev;
}
/**
* Sets the next node in the list.
*
* #param n the next node in the list
*/
public void setNext(Node n) {
next = n;
}
/**
* Sets the previous node in the list.
*
* #param n the previous node in the list
*/
public void setPrev(Node n) {
prev = n;
}
}
So far this is what I have and I am just trying whatever I can:
public static boolean listPalindrome(Node input) {
if(input == null)
{
throw new IllegalArgumentException();
}
int count = 0;
while(input.next != null)
{
count++;
}
Node holder = new Node(null, input.next);
for(int i = 0;i<count;i++)
{
if(input.next != null)
{
break;
}
else
{
}
}
return false; //replace this
}
Please help!
Thanks!
You have an infinite loop with count++. input.next will always be non-null since you aren't updating the value of input in the loop.
If you were to get past that there is no reason to declare a new Node in your code. The loop you have also will break on the first iteration assuming the linked list is a size > 0, you should instead check input.next == null but put it at the end of the loop.
Also noting that your a GMU student it would be an honor code violation for me to help you any more than this ;)
So I am working on a hashmap that uses two distinct hash functions to create it. The problem is in my iterator class I am getting an error that reads <anonymous hashmap.MyHashMap$1> is not abstract and does not override method in remove() in iterator. I have tried everything to figure out how to get this error to go away. I cannot simply "implement all abstract methods" as it suggests as otherwise I can't initialize the hash function and use it to insert values. Below is the entirety of my code
import java.util.Map;
import java.util.Iterator;
public class MyHashMap<KeyType, ValueType> implements
Iterable<Map.Entry<KeyType, ValueType>> {
// The size of the array
int theSize = 0;
// The starting size of the table
public static final int DEFAULT_ARRAY_SIZE = 11;
// Array containing the number of nodes in each index of the array
int lengths[] = null;
// The array used for the hash table
private Node<KeyType, ValueType>[] arr = null;
private HashFunction<KeyType> hash1; //One of the two hash functions
private HashFunction<KeyType> hash2; //One of the two hash functions
/**
* Null constructor for the myHashMap object
*/
public MyHashMap() {
this(null, null);
}
/**
* Accepts two hash functions to generate a hash code
*
* #param h1 The first hash function
* #param h2 The second hash function
*/
public MyHashMap(HashFunction<KeyType> h1, HashFunction<KeyType> h2) {
hash1 = h1;
hash2 = h2;
doClear();
}
/**
* Returns the size of the table
*/
public int size() {
return theSize;
}
/**
* Performs the clear private routine
*/
public void clear() {
doClear();
}
/**
* Clears the table
*/
private void doClear() {
theSize = 0;
arr = new Node[DEFAULT_ARRAY_SIZE];
lengths = new int[DEFAULT_ARRAY_SIZE];
}
/**
* Resizes the hash table if the size passes the default size
*/
private void rehash() {
MyHashMap<KeyType, ValueType> bigger
= new MyHashMap<KeyType, ValueType>(hash1, hash2);
bigger.arr = new Node[arr.length * 2];
bigger.lengths = new int[bigger.arr.length];
for (Node<KeyType, ValueType> lst : arr) {
for (Node<KeyType, ValueType> p = lst; p != null; p = p.next) {
bigger.put(p.key, p.value);
}
}
arr = bigger.arr;
lengths = bigger.lengths;
bigger = null;
}
/**
* Generates a hash code in order to determine where on the table the item
* goes
*
* #param k The key that will be used to generate the code
* #param h The hash function to be used
* #return The index
*/
private int myHash(KeyType k, HashFunction<KeyType> hash) {
if (hash == null) {
return Math.abs(k.hashCode() % arr.length);
} else {
return Math.abs(hash.hashCode(k) % arr.length);
}
}
/**
* Places an item into the hash map. If the key matches an existing one, the
* value is then replaced with the new incoming value
*
* #param k The incoming key
* #param v The incoming value
* #return The the old value removed.
*/
public ValueType put(KeyType k, ValueType v) {
// If the size of the table exceeds the default array size, rehash
if (size() > arr.length) {
rehash();
}
// The hash codes obtained from the key
int thisList1 = myHash(k, hash1);
int thisList2 = myHash(k, hash2);
// Checking if the incoming key matches an existing key, if it does
// replace the value and return the old one
for (Node<KeyType, ValueType> p = arr[thisList1]; p != null; p = p.next) {
if (p.key.equals(k)) {
ValueType old = p.value;
p.value = v;
return old;
}
}
for (Node<KeyType, ValueType> p = arr[thisList2]; p != null; p = p.next) {
if (p.key.equals(k)) {
ValueType old = p.value;
p.value = v;
return old;
}
}
// Adding the incoming data to the index with the least amount of
// nodes in it.
if (numOfNodes(arr[thisList1]) <= numOfNodes(arr[thisList2])) {
arr[thisList1] = new Node<>(k, v, arr[thisList1]);
++lengths[thisList1];
++theSize;
} else {
// Else the second list is the smaller of the two. Add it to this one
arr[thisList2] = new Node<>(k, v, arr[thisList2]);
++lengths[thisList2];
++theSize;
}
// No old value to return
return null;
}
/**
* Counts the number of nodes that exist in a space of the table
*
* #param n The start space
* #return The number of nodes
*/
private int numOfNodes(Node n) {
int size = 0;
// If the space is not empty, then it will step through and count the
// number of nodes present
for (Node<KeyType, ValueType> p = n; p != null; p = p.next) {
++size;
}
return size;
}
/**
* Removes a specified key from the map
* #param k The key that is to be removed
* #return True if the object has been removed, false if it has not
*/
public boolean remove(KeyType k) {
// Getting the hash codes for the list
int thisList1 = myHash(k, hash1);
int thisList2 = myHash(k, hash2);
// If the position specified by hash1 is found, check first element
if (arr[thisList1] != null) {
if (arr[thisList1].key.equals(k)) {
arr[thisList1] = arr[thisList1].next;
--theSize;
return true;
}
for (Node<KeyType, ValueType> p = arr[thisList1]; p.next != null;
p = p.next) {
if (p.next.key.equals(k)) {
p.next = p.next.next;
--theSize;
return true;
}
}
}
// If the position specified by hash2 is found, check first element
if (arr[thisList2] != null) {
if (arr[thisList2].key.equals(k)) {
arr[thisList2] = arr[thisList2].next;
--theSize;
return true;
}
for (Node<KeyType, ValueType> p = arr[thisList2]; p.next != null;
p = p.next) {
if (p.next.key.equals(k)) {
p.next = p.next.next;
--theSize;
return true;
}
}
}
// Else the item that is to removed is never found, therefore return
// false
return false;
}
/**
* Returns the desired value associated with the specified key
*
* #param k The key
* #return The value if found, null if not
*/
public ValueType get(KeyType k) {
// The hash codes obtained from the key
int thisList1 = myHash(k, hash1);
int thisList2 = myHash(k, hash2);
// Using the first hash code, searching the nodes
for (Node<KeyType, ValueType> p = arr[thisList1]; p != null; p = p.next) {
if (p.key.equals(k)) {
return p.value;
}
}
// Using the second hash code, seraching the nodes
for (Node<KeyType, ValueType> p = arr[thisList2]; p != null; p = p.next) {
if (p.key.equals(k)) {
return p.value;
}
}
return null;
}
/**
* Prints out the hashMap
*
* #return The printed hashMap
*/
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for(Map.Entry<KeyType, ValueType> n : this) {
sb.append(n);
sb.append(",");
}
sb.append("]");
return new String(sb);
}
/**
* Creates an iterator for traversing the list.
*
* #return An iterator to traverse the list
*/
#Override
public Iterator<Map.Entry<KeyType, ValueType>> iterator() {
return new Iterator<Map.Entry<KeyType, ValueType>>() {
/**
* Checks if the node has a next link
* #return True if it has a node, false if it does not
*/
#Override
public boolean hasNext() {
return current != null;
}
/**
* Gets the next item on the list
* #return The next node
*/
#Override
public Map.Entry<KeyType, ValueType> next() {
final Node<KeyType, ValueType> theCurrent = current;
current = current.next;
// If the current list has no more nodes, move to the next list
if (current == null) {
++listNum;
advanceToNewList();
}
// Creates a new entry that will hold the next node
Map.Entry<KeyType, ValueType> nextItem = new Map.Entry<KeyType, ValueType>() {
/**
* Returns the current node's key
* #return
*/
#Override
public KeyType getKey() {
return theCurrent.key;
}
/**
* Returns the current node's value
* #return
*/
#Override
public ValueType getValue() {
return theCurrent.value;
}
/**
* Sets a new value to the current node
* #param value The new value that will be placed
* #return The old value that was overwritten
*/
#Override
public ValueType setValue(ValueType value) {
ValueType temp = theCurrent.value;
theCurrent.value = value;
return temp;
}
};
return nextItem;
}
/**
* Advances to the next index of the table
*/
private void advanceToNewList() {
while (listNum < arr.length && arr[ listNum ] == null) {
listNum++;
}
if (listNum != arr.length) {
current = arr[listNum];
}
}
// Initializes the advanceToNewList method {
advanceToNewList();
}
Node<KeyType, ValueType> current; // current node
int listNum; // current list #
};
}
/**
* Creates a node class for the linked list
* #param <KeyType> The key for the map. Can be any type
* #param <ValueType> The value associated with the key. Can be any type
*/
class Node<KeyType, ValueType> {
/**
* Constructs a node object using a key, a value, and a link to the next
* node
* #param k The key
* #param v The value
* #param n The next node
*/
Node(KeyType k, ValueType v, Node<KeyType, ValueType> n) {
key = k;
value = v;
next = n;
}
/**
* Prints out the node
* #return A string containing the key and the value
*/
public String toString() {
return key + "=" + value;
}
KeyType key; // The key of the node
ValueType value; // The value of the node
Node<KeyType, ValueType> next; // The next node
}
/**
* Creates an array that contains the number of entries that have a
* certain length. For example: The number of lists of length 0, 1, 2, etc.
* #return The array containing the distribution of list lengths
*/
public int[] getLengths()
{
int sizeList[] = new int[20];
// Incrementing the count at the index in the array sizeList. It will
// increment for every list of size at lengths[i].
for(int i = 0; i < lengths.length; ++i) {
++sizeList[lengths[i]];
}
return sizeList;
}
}
Below is the specific location where the error occurs
public Iterator<Map.Entry<KeyType, ValueType>> iterator() {
return new Iterator<Map.Entry<KeyType, ValueType>>()
{ <--- Right here is where the error occurs
Any help that can be provided will be greatly appreciated
Short answer: When creating anonymous classes of an interface, you must implement every abstract method. You don't necessarily need to thoroughly implement every method, you must just create it even if it has blank contents. So, you can just do this to rid the error (starting at the arrow where the exception was raised) :
public void remove() {
//No contents
}
and do the same things for any other abstract methods in the Iterator interface. However, it is probably best that you do actually write some code for these...
I've written my own implementations of a Stack and a Queue, but I've made them work specifically for integers. I am well aware of the Java implementations, java.util.Stack and java.util.Queue, but I'm doing this as a learning experience... just want to learn something new. How would I make these generic implementations such that I can store any object in my Stack/Queue, not just integers?
Below is the code, but I also welcome all critique and suggestions on improvements. I would like to know what I've done well and what I haven't done well.
STACK NODE IMPLEMENTATION
public class StackNode {
public Integer value;
public StackNode() {
this.value = null;
}
public StackNode(StackNode node) {
this.value = node.value;
}
public StackNode(Integer data) {
this.value = data;
}
}
STACK IMPLEMENTATION
/**
* Stack Data Structure.
*
* A Stack is a last in, first out (LIFO) data structure. A Stack can have any abstract data type as an element, but is
* characterized by two fundamental operations: push() and pop(). The push() operation adds an element to the top of the Stack,
* hiding any elements already on the Stack, or initializing the Stack if it is empty. The pop() operation removes an element
* from the top of the Stack, and returns this element's value to the caller. Elements are removed from the Stack in the reverse
* order to the order of their addition to the Stack; therefore, lower elements are those that have been on the Stack the
* longest, thus, the first element added to the Stack will be the last one to be removed.
*
* #author Hristo
*/
public class Stack {
private int size;
private int capacity;
private int topNodeIndex;
private Object[] theStack;
/**
* Default Constructor. Initalizes this Stack with initial size = 0 and capacity = 1.
*/
public Stack() {
this.size = 0;
this.capacity = 1;
this.topNodeIndex = -1;
this.theStack = new Object[capacity];
}
/**
* Constructor. Initializes a Stack to have the given capacity.
*
* #param capacity - the capacity of the Stack-to-be
*/
public Stack(int capacity) {
this.size = 0;
this.capacity = capacity;
this.topNodeIndex = -1;
this.theStack = new Object[capacity];
}
/**
* Returns the size of this Stack, i.e., how many elements are in this Stack.
*
* #return int - the size of this Stack
*/
public int size() {
return this.size;
}
/**
* Returns the capacity of this Stack, i.e., the maximum number of elements this Stack can hold.
*
* #return int - the capacity of this Stack
*/
public int capacity() {
return this.capacity;
}
/**
* Returns whether or not this Stack is empty, i.e., size == 0.
*
* #return boolean - true if this Stack is empty, false otherwise
*/
public boolean isEmpty() {
return ((this.topNodeIndex == -1) && (this.size == 0)) ? true : false;
}
/**
* Returns whether or not this Stack is full, i.e., size == capacity.
*
* #return boolean - true if this Stack is full, false otherwise
*/
public boolean isFull() {
return (this.size == this.capacity) ? true : false;
}
/**
* Pushes the given value onto the top of this Stack.
*
* #param value - the data to push
*/
public void push(Integer value) {
if (value == null) {
return;
} else {
if (isFull()) {
resize();
}
insert(value);
return;
}
}
/**
* Removes the top element of this Stack and returns the corresponding value.
*
* #return Integer - the value of the top element of this Stack
*/
public Integer pop() {
if (isEmpty()) {
return null;
} else {
return remove();
}
}
/**
* Returns the top element of this Stack without removing it.
*
* #return Integer - the top element of this Stack
*/
public Integer peek() {
return (isEmpty()) ? null : (((StackNode) theStack[this.topNodeIndex]).value);
}
/**
* Inserts the given value onto this Stack.
*
* #param value - the value to insert
*/
private void insert(Integer value) {
theStack[this.topNodeIndex + 1] = new StackNode(value);
this.topNodeIndex++;
this.size++;
return;
}
/**
* Removes the top element of this Stack and returns the corresponding value.
*/
private Integer remove() {
StackNode topNode = (StackNode) theStack[this.topNodeIndex];
theStack[this.topNodeIndex] = null;
this.topNodeIndex--;
this.size--;
return topNode.value;
}
/**
* Creates an array with double the size of the original and copies over the contents from the original.
*/
private void resize() {
Object[] doubleStack = new Object[this.capacity * 2];
for (int index = 0; index < this.size; index++) {
doubleStack[index] = theStack[index];
}
theStack = doubleStack;
capacity *= 2;
return;
}
}
QUEUE NODE IMPLEMENTATION
public class QueueNode {
public Integer value;
public QueueNode() {
this.value = null;
}
public QueueNode(QueueNode node) {
this.value = node.value;
}
public QueueNode(Integer data) {
this.value = data;
}
}
QUEUE IMPLEMENTATION
/**
* Queue Data Structure.
*
* A Queue is a first in, first out (FIFO) data structure. A Queue can have any abstract data type as an element, but is
* characterized by two fundamental operations: enqueue() and dequeue(). The enqueue() operation adds an element to the front of
* the Queue, hiding any elements already in the Queue, or initializing the Queue if it is empty. The dequeue() operation
* removes an element from the front of the Queue, and returns this element's value to the caller. Elements are removed from the
* Queue in the same order to the order of their addition to the Queue; therefore, the first element added to the Queue will be
* the first one to be removed.
*
* #author Hristo
*/
public class Queue {
private int size;
private int capacity;
private int theEndIndex;
private int theFrontIndex;
private Object[] theQueue;
/**
* Default Constructor. Initalizes this Queue with initial size = 0 and capacity = 1.
*/
public Queue() {
this.size = 0;
this.capacity = 1;
this.theEndIndex = -1;
this.theFrontIndex = -1;
this.theQueue = new Object[this.capacity];
}
/**
* Constructor. Initializes a Queue to have the given capacity.
*
* #param capacity - the capacity of the Queue-to-be
*/
public Queue(int capacity) {
this.size = 0;
this.capacity = capacity;
this.theEndIndex = -1;
this.theFrontIndex = -1;
this.theQueue = new Object[capacity];
}
/**
* Returns the size of this Queue, i.e., how many elements are in this Queue.
*
* #return int - the size of this Queue
*/
public int size() {
return this.size;
}
/**
* Returns the capacity of this Queue, i.e., the maximum number of elements this Queue can hold.
*
* #return int - the capacity of this Queue
*/
public int capacity() {
return this.capacity;
}
/**
* Returns whether or not this Queue is empty, i.e., size == 0.
*
* #return boolean - true if this Queue is empty, false otherwise
*/
public boolean isEmpty() {
return ((this.theEndIndex == this.theFrontIndex) && (this.size == 0)) ? true : false;
}
/**
* Returns whether or not this Queue is full, i.e., size == capacity.
*
* #return boolean - true if this Queue is full, false otherwise
*/
public boolean isFull() {
return (this.size == this.capacity && this.theEndIndex == this.theFrontIndex) ? true : false;
}
/**
* Inserts the given value onto the end of this Queue.
*
* #param value - the data to insert
*/
public void enqueue(Integer value) {
if (value == null) {
return;
} else {
if (isEmpty()) {
this.theEndIndex = 0;
this.theFrontIndex = 0;
}
if (isFull()) {
resize();
}
insert(value);
return;
}
}
/**
* Removes the front element in this Queue and returns it.
*
* #return Integer - the front element in this Queue
*/
public Integer dequeue() {
if (isEmpty()) {
return null;
} else {
return remove();
}
}
/**
* Returns the front element of this Queue without removing it.
*
* #return Integer - the front element of this Queue
*/
public Integer peek() {
return (isEmpty()) ? null : (((QueueNode) theQueue[this.theFrontIndex]).value);
}
/**
* Inserts the given value into this Queue.
*
* #param value - the value to insert
*/
private void insert(Integer value) {
this.theQueue[this.theEndIndex] = new QueueNode(value);
/*
* 'theEndIndex' pointer indicates where to insert new QueueNodes in 'theQueue' array. If incrementing this pointer goes
* beyond the size of 'theQueue' array, then pointer needs to wrap around to the beggining of 'theQueue' array.
*/
this.theEndIndex++;
if (this.theEndIndex >= this.theQueue.length) {
this.theEndIndex = 0; // wrap around
}
this.size++;
return;
}
/**
* Removes the front element in this Queue and returns the corresponding value.
*/
private Integer remove() {
QueueNode node = (QueueNode) this.theQueue[this.theFrontIndex];
theQueue[this.theFrontIndex] = null;
/*
* 'theFrontIndex' pointer indicates where to remove QueueNodes from 'theQueue' array. If incrementing this pointer goes
* beyond the size of 'theQueue' array, then pointer needs to wrap around to the beggining of 'theQueue' array.
*/
this.theFrontIndex++;
if (this.theFrontIndex >= this.theQueue.length) {
this.theFrontIndex = 0; // wrap around
}
this.size--;
return node.value;
}
/**
* Creates an array with double the size of the original and copies over the contents from the original.
*/
private void resize() {
Object[] doubleQueue = new Object[this.capacity * 2];
int count = 0;
int iter = this.theFrontIndex;
while (count < this.size) {
doubleQueue[count] = (QueueNode) theQueue[iter];
iter++;
count++;
if (iter >= this.size && this.size > 1) {
iter = 0;
}
}
this.theQueue = doubleQueue;
this.capacity *= 2;
this.theEndIndex = this.size;
this.theFrontIndex = 0;
return;
}
}
Like this (you add the rest):
public class StackNode<T>
{
public T value;
}
public class Stack<T>
{
private int size;
private int capacity;
private int topNodeIndex;
private StackNode<T>[] theStack;
}
The placeholder T describes the type of value help by the node class. So you can create a Stack<Double> or a Stack<Process> or any other type that you wish.