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.
Related
I am working to write code to Evaluate the given postfix expression. I have wrote a code, but one of the junit test doesn´t go through. How should i write that "expr contains too few operands". In the evalute I use a stack.
TODO: help to correct the "evaluate(String expr) throws ExpressionException ()" method so all the test in the testclass goes through.
EDIT: The test that i need help withy is the only in the JUNIT test class.
Interface stack:
/**
* A interface of stack
*/
public interface Stack <T> {
/**
* Adds the element to the top of the stack.
*/
void push (T elem);
/**
* Removes and returns the top element in stack,
* that is the element that was last added.
* Throws an EmptyStackException if stack is empty.
*/
T pop();
/**
* Returns the top element in the stack without removing it.
* Throws an EmptyStackException if stack is empty.
*/
T top();
/**
* Returns the number of elements in stack.
* #return the number of elements.
*/
int size();
/**
* Returns true if the stack is empty.
* #return true.
*/
boolean isEmpty();
}
Linkedlist implements stack:
import java.util.EmptyStackException;
import java.util.NoSuchElementException;
/**
* A singly linked list.
*
*/
public class LinkedList<T> implements Stack <T> {
private ListElement<T> first; // First element in list.
private ListElement<T> last; // Last element in list.
private int size; // Number of elements in list.
/**
* A list element.
*/
private static class ListElement<T>{
public T data;
public ListElement<T> next;
public ListElement(T data) {
this.data = data;
this.next = null;
}
}
/**
* Creates an empty list.
*/
public LinkedList() {
this.first = null;
this.last = null;
this.size = 0;
}
/**
* Inserts the given element at the beginning of this list.
*
* #param element An element to insert into the list.
*/
public void addFirst(T element) {
ListElement<T> firstElement = new ListElement<>(element);
if (this.size == 0){
this.first = firstElement;
this.last = firstElement;
}
else{
firstElement.next = this.first;
this.first = firstElement;
}
this.size ++;
}
/**
* Inserts the given element at the end of this list.
*
* #param element An element to insert into the list.
*/
public void addLast(T element) {
ListElement<T> lastElement = new ListElement<>(element);
if(this.size ==0){
this.first = lastElement;
}
else{
this.last.next = lastElement;
}
this.last = lastElement;
this.size ++;
}
/**
* #return The head of the list.
* #throws NoSuchElementException if the list is empty.
*/
public T getFirst() {
if (this.first != null){
return this.first.data;
}
else{
throw new NoSuchElementException();
}
}
/**
* #return The tail of the list.
* #throws NoSuchElementException if the list is empty.
*/
public T getLast() {
if(this.last != null){
return this.last.data;
}
else{
throw new NoSuchElementException();
}
}
/**
* Returns an element from a specified index.
*
* #param index A list index.
* #return The element at the specified index.
* #throws IndexOutOfBoundsException if the index is out of bounds.
*/
public T get(int index) {
if(index < 0|| index >= this.size){
throw new IndexOutOfBoundsException();
}
else{
ListElement<T>element = this.first;
for(int i = 0; i < index; i++){
element = element.next;
}
return element.data;
}
}
/**
* Removes the first element from the list.
*
* #return The removed element.
* #throws NoSuchElementException if the list is empty.
*/
public T removeFirst() {
if(this.first != null || this.size != 0){
ListElement<T> list = this.first;
this.first = first.next;
size --;
return list.data;
}
else{
throw new NoSuchElementException();
}
}
/**
* Removes all of the elements from the list.
*/
public void clear() {
this.first = null;
this.last = null;
this.size =0;
}
/**
* Adds the element to the top of the stock.
* #param elem
*/
#Override
public void push(T elem) {
ListElement <T> list = new ListElement<>(elem);
if( first == null){
first = list;
last = first;
} else{
list.next = first;
first = list;
}
size ++;
}
/**
* Removes and returns the top element in stack,
* that is the element that was last added.
* Throws an EmptyStackException if stack is empty.
* #return the top element in the stack.
*/
#Override
public T pop(){
if(isEmpty()){
throw new EmptyStackException();
}else{
ListElement <T> list = first;
first = first.next;
size --;
return list.data;
}
}
/**
* returns the top element in the stack without removing it.
* Throws an EmptyStackException if stack is empty.
* #return the top element.
*/
#Override
public T top() {
if(isEmpty()){
throw new EmptyStackException();
}else{
return first.data;
}
}
/**
* Returns the number of elements in the stock
* #return The number of elements in the stock.
*/
public int size() {
return this.size;
}
/**
* Note that by definition, the list is empty if both first and last
* are null, regardless of what value the size field holds (it should
* be 0, otherwise something is wrong).
*
* #return <code>true</code> if this list contains no elements.
*/
public boolean isEmpty() {
return first == null && last == null;
}
/**
* Creates a string representation of this list. The string
* representation consists of a list of the elements enclosed in
* square brackets ("[]"). Adjacent elements are separated by the
* characters ", " (comma and space). Elements are converted to
* strings by the method toString() inherited from Object.
*
* Examples:
* "[1, 4, 2, 3, 44]"
* "[]"
*
* #return A string representing the list.
*/
public String toString() {
ListElement<T> listOfElements = this.first;
String returnString = "[";
while(listOfElements != null) {
returnString += listOfElements.data;
if(listOfElements.next != null){
returnString += ", ";
}
listOfElements = listOfElements.next;
}
returnString += "]";
return returnString;
}
}
Postfix class:
import java.util.Scanner;
import java.util.Stack;
/**
* The Postfix class implements an evaluator for integer postfix expressions.
*
* Postfix notation is a simple way to define and write arithmetic expressions
* without the need for parentheses or priority rules. For example, the postfix
* expression "1 2 - 3 4 + *" corresponds to the ordinary infix expression
* "(1 - 2) * (3 + 4)". The expressions may contain decimal 32-bit integer
* operands and the four operators +, -, *, and /. Operators and operands must
* be separated by whitespace.
*
*/
public class Postfix {
public static class ExpressionException extends Exception {
public ExpressionException(String message) {
super(message);
}
}
/**
* Evaluates the given postfix expression.
*
* #param expr Arithmetic expression in postfix notation
* #return The value of the evaluated expression
* #throws ExpressionException if the expression is wrong
*/
public static int evaluate(String expr) throws ExpressionException {
expr = expr.trim();
String[] tokens = expr.split("\\s+");
if(expr.matches("(\\+)|(\\-)|(\\*)|(\\/)")){
throw new ExpressionException("");
}
LinkedList<Integer> stack = new LinkedList<>();
for(String token: tokens) {
if(isInteger(token)) {
int number = Integer.parseInt(token);
stack.push(number);
}
else if(isOperator(token)) {
String operator = token;
int b = stack.pop();
int a = stack.pop();
if(token.equals("+")){
stack.push(a+b);
} else if (token.equals("-")){
stack.push(a-b);
}
else if(token.equals("/")){
if( b == 0){
throw new ExpressionException("");
}
stack.push(a/b);
} else if(token.equals("*")){
stack.push(a*b);
}
}
else {
throw new ExpressionException("");
}
}
if(stack.size() != 1){
throw new ExpressionException("");
}
int result = stack.pop();
if(stack.isEmpty()) {
throw new ExpressionException("");
}
return result;
}
/**
* Returns true if s is an operator.
*
* A word of caution on using the String.matches method: it returns true
* if and only if the whole given string matches the regex. Therefore
* using the regex "[0-9]" is equivalent to "^[0-9]$".
*
* An operator is one of '+', '-', '*', '/'.
*/
private static boolean isOperator(String s) {
return s.matches("[-+*/]");
}
/**
* Returns true if s is an integer.
*
* A word of caution on using the String.matches method: it returns true
* if and only if the whole given string matches the regex. Therefore
* using the regex "[0-9]" is equivalent to "^[0-9]$".
*
* We accept two types of integers:
*
* - the first type consists of an optional '-'
* followed by a non-zero digit
* followed by zero or more digits,
*
* - the second type consists of an optional '-'
* followed by a single '0'.
*/
private static boolean isInteger(String s) {
return s.matches("(((\\-)*?[1-9](\\d+)*)|(\\-)*?0)");
}
}
Junit class
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.CoreMatchers.*;
import java.util.Arrays;
/**
* Test class for Postfix
*
*/
public class PostfixTest {
#Rule public Timeout globalTimeout = Timeout.seconds(5);
#Test
public void evaluateExceptionWhenExprContainsTooFewOperands() {
String[] expressions = {"1 +", " 1 2 + +"};
assertExpressionExceptionOnAll(expressions);
}
}
Your pop() method will throw an exception when the stack is empty (which you can catch) and your isEmpty() method will return true when the stack is empty. You can also use the size() method to check the number of items on the stack. As an example, you can use code like this to check if there are enough values to run your operand:
// ...
else if(isOperator(token)) {
String operator = token;
if (stack.size() < 2) {
throw new ExpressionException("There are not enough values on the stack to perform the operation");
}
int b = stack.pop();
int a = stack.pop();
// ...
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.
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've been trying to define an immutable ConsList in Java, somewhat like how Lists work in Scala. Each prepending creates a new view of the list (starting with the new head) and returns it. Here's what I have so far, which all compiles and runs correctly.
package common.dataStructures;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;
/**
* An immutable collection representing a Cons List.
* All Cons Lists are terminated with a Nil element (no tail, no value),
* but this element is hidden from iteration and stringing when there
* are non-nil elements in the list.
* <br><br>
* Because the List is immutable, different lists can be branched off of a shared
* tail without altering the tail. This makes the ConsList useful in some algorithms
* that require exploring different possibility chains without altering earlier
* sub-chains.
*
* #param <E> - the generic type of elements stored within the lst.
* No methods are ever called on elements of type E, so no requirements
* are made of the type.
* #author Mshnik
*/
public class ConsList<E> implements Iterable<E> {
/**
* A string used for toString implementations for the Nil element of
* a Cons List
*/
public static final String NIL_STRING = "_NIL_";
/**
* The tail of this List.
* If this is Nil, tail is null. Otherwise, this is another ConsList
* of one smaller size.
*/
private final ConsList<E> tail;
/**
* The value stored in the head of this list.
* If this is Nil, value is null. Otherwise the value may be null,
* or the value stored in the head.
*/
public final E val;
/**
* The size of this list. Because ConsLists are immutable, this size
* value is immutable. If this is Nil, size is 0. Otherwise, size
* is some positive, non-zero value
*/
public final int size;
/**
* Initializes an empty (NIL) ConsList, with tail = null, val = null,
* size = 0. <br>
* A Nil element is required to be at the end of every ConsList,
* so this constructor is used to start any ConsList. Elements are then
* cons (prepended) on to this element to build a list.
*/
public ConsList() {
val = null;
tail = null;
size = 0;
}
/**
* Creates a new head of a list
*
* #param val - the value to store in the head of this list
* #param tail - the tail of this list, an existing ConsList
* #param size - the size of this list
*/
private ConsList(E val, ConsList<E> tail, int size) {
this.val = val;
this.size = size;
this.tail = tail;
if (val == null || tail == null || size < 1)
throw new RuntimeException("Illegal ConsList construction" + this);
}
/**
* Returns the value stored in the head of this ConsList
*/
public E value() {
return val;
}
/**
* Returns the tail of this ConsList. Returns null if this is NIL
*/
public ConsList<E> tail() {
return tail;
}
/**
* Returns true if this is NIL - the trailing element in a consList.
* A Nil element has no tail and no value
*/
public boolean isNil() {
return tail() == null && val == null;
}
/**
* Returns true if this is the last element in a list.
* Returns true for NIL elements, and the last real element before a NIL element
* Used to stop iteration before it reaches the NIL terminator
*/
public boolean isLast() {
return isNil() || tail().tail() == null && tail().val == null;
}
/**
* Returns a new ConsList that consists of {#code head} prepended
* onto this ConsList
*/
public ConsList<E> cons(E head) {
return new ConsList<E>(head, this, size + 1);
}
/**
* Returns a new ConsList that consists of this full list, reversed.
*/
public ConsList<E> reverse() {
ConsList<E> reversed = new ConsList<E>();
ConsList<E> ptr = this;
while (!ptr.isNil()) {
reversed = reversed.cons(ptr.val);
ptr = ptr.tail;
}
return reversed;
}
/**
* Returns a string representation of a ConsList
*/
#Override
public String toString() {
String s = "(";
ConsList<E> current = this;
while (current != null) {
if (current.val == null && current.tail() == null) {
if (current == this) s += NIL_STRING + ",";
} else {
s += current.val + ",";
}
current = current.tail();
}
return s.substring(0, s.length() - 1) + ")";
}
/**
* Returns true if this equals {#code o}.
* Two ConsLists are equal if they are the same length and every value they
* at each index are equal.
*/
#Override
public boolean equals(Object o) {
if (!(o instanceof ConsList<?>) || o == null) return false;
ConsList<?> lst = (ConsList<?>) o;
return size == lst.size && Objects.equals(val, lst.val) && Objects.equals(tail(), lst.tail());
}
/**
* Returns the size of this list. See {#link common.dataStructures.ConsList#size}
*/
public int size() {
return size;
}
/**
* Returns true iff the size of this list is 0. Equivalently, if this list is NIL
*/
public boolean isEmpty() {
return size == 0;
}
/**
* Returns true iff this list contains the Object o.
* NIL lists do not contain any elements, thus calling contains on a NIL
* list for any input will always return false.
*/
public boolean contains(Object o) {
return !isNil() && (Objects.equals(val, o) || !isLast() && tail().contains(o));
}
/**
* Returns true iff, for all {#code Object o : c}, this.contains(o)
*/
public boolean containsAll(Collection<?> c) {
for (Object o : c) {
if (!contains(o)) return false;
}
return true;
}
/**
* Returns an Iterator over the elements in this ConsList.
* As ConsLists are immutable, the returned iterator does not support removal,
* and cannot throw a ConcurrentModificationException.
* The iterator returned will stop at the last real element in the list,
* *before* the NIL element that terminates all lists. If this method
* is called on the NIL list, the iterator will have no elements to return -
* hasNext() will immediately return false. Thus the iterator behaves as if
* the NIL element does not exist.
*/
#Override
public Iterator<E> iterator() {
return new ConsIterator<E>(this);
}
/**
* Converts this ConsList to an array of Objects.
* The length of the returned array is equal to this.size.
* Therefore for the NIL array, the returned array is of length 0.
*/
public Object[] toArray() {
Object[] arr = new Object[size];
ConsList<E> current = this;
for (int i = 0; i < size; i++, current = current.tail()) {
arr[i] = current.val;
}
return arr;
}
/**
* Converts this ConsList to an array of type T.
* The length of the returned array is equal to Max(this.size, arr.length).
* Therefore for the NIL array, the returned array is of length 0.
* See the List interface for the weird type bullcrap about casting to T[]
*/
#SuppressWarnings("unchecked")
public <T> T[] toArray(T[] arr) {
if (arr.length < size) {
arr = Arrays.copyOf(arr, size);
}
ConsList<E> current = this;
for (int i = 0; i < size; i++, current = current.tail()) {
arr[i] = (T) current.val;
}
return arr;
}
/**
* Returns the {#code index}th element in this list.
*
* #throws IllegalArgumentException - if index < 0 or index >= size - thus throws
* exception if this is called with any index value on the nil list
*/
public E get(int index) {
if (index < 0 || index >= size)
throw new IllegalArgumentException("Can't get element at index " + index + " OOB");
if (index == 0) return val;
return tail().get(index - 1);
}
/**
* Returns the first index of {#code o} in this List, or -1 if it does not occur
*/
public int indexOf(Object o) {
return indexOf(o, 0);
}
/**
* Helper method for the indexOf function - keeps track of how many recursive
* calls have been made thus far to this function to return the correct value
* if {#code o} is found.
*/
private int indexOf(Object o, int x) {
if (Objects.equals(val, o)) return x;
else if (isLast()) return -1;
return tail().indexOf(o, x + 1);
}
/**
* Helper class for iterating over ConsList
* Keeps track of a current list element that will be returned by next() calls.
*
* #param <E>
* #author Mshnik
*/
public static class ConsIterator<E> implements Iterator<E> {
private ConsList<E> current; //next element to return when next() is called
/**
* Creates a new ConsIterator, starting at first
*/
public ConsIterator(ConsList<E> first) {
current = first;
}
/**
* Returns true iff there is another element to iterate over.
* Specifically, returns {#code !current.isNil()}
*/
#Override
public boolean hasNext() {
return !current.isNil();
}
/**
* Returns the next value in this iteration, and moves current
* forward one element.
*/
#Override
public E next() {
E val = current.val;
current = current.tail();
return val;
}
}
}
This all works for type E and covartiants thereof. If I have a ConsList<Animal>, and I call cons(new Dog()), it will give me a ConsList<Animal>, as desired.
However, I've tried every what I can think of to define a contravariant cons method. My best guess looks roughly like this:
public <X super E> ConsList<X> cons(X head) {
return new ConsList(head, this, size+1);
}
Which I would hope would allow me to create a ConsList<String>, cons on new Object and receive a ConsList<Object>.
But this approach doesn't compile, nor does any other attempt I've made. I understand why mutable data structures (i.e. ArrayList) do not support covariance or contravariance, but is there any syntactically valid way to define generic contravariance in Java, even for immutable structures? If so, what is it, and if not, why?
Remark: This is not a complete answer, but it gives an idea how to solve it by pushing some checks to runtime and adding the class-information.
The other question about 'why', i can't answer.
You need to pass an object and the class of the object. Your compiler will here throw an exception if the class is not super E. Although the check if head is really an instance of clazz needs to be done manually.
public <T> ConsList<T> cons(final T head, final Class<? super E> clazz) {
if (clazz.isInstance(head) && head.getClass().equals(clazz)) {
return new ConsList(head, this, this.size + 1);
} else {
throw new IllegalArgumentException("T is not instance of class");
}
}
It is not size as you need to pass the class. But at least you can call it like:
list.cons(headElement, headElement.getClass());
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...