I want them to do a custom iterator, for a wrapper set.
ListIterator from(E elem)
Extend the implementation and add some façade methods
If you want a custom iterator for a Map, do need to use a LinkedHashMap (which iterates in the same order as entries are added). Just use a HashMap and override the entrySet() method:
public class Map<K, V> extends HashMap<K, V> {
public Set<K, V> entrySet() {
return new HashSet<K, V>(super.entrySet()) {
public Iterator<Map.Entry<K, V>> iterator () {
return // some custom implementation
}
};
}
// similar for keySet() if you wish
}
I've got a solution now that doesn't use extension or reflection (or indeed LinkedHashMap)
What do you think?
package i3.util;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Map;
import java.util.NoSuchElementException;
/**
* This class is a like LinkedHashSet (insertion order) but it allows querying
* the relative position of a element and has a ListIterator that can set and
* insert anywhere.
*
* Warning: the iterator can change the order of the set by moving elements when
* setting or adding. Elements that already exist are not ignored, but moved the
* requested place. This changes iteration order
*
*
* The iterators of this class are fail fast and will throw a
* ConcurrentModificationException if their iterator are used with intervening
* main class (or other iterators) mutative calls
*
* #author i30817 <i30817#gmail.com>
*/
public class LinkedSet<E> extends AbstractSet<E> {
//It holds the linked list
private Map<E, Node> m = new HashMap<E, Node>();
//head of that
protected Node head = new Node();
//this is copied to the map value in increments of iteratorAddStep on set.add
//(which only adds to the end, by insertion indexing)
private int monotonicallyIncreasing = 0;
//iterator add step may change when doing rebuilds of the 'space' between elements
//for the before/after functions on LinkedKeyIterator.add
private int iteratorAddStep = 10;
//for fail fast iterators
private int modCount;
/**
* Start iterating from elem (inclusive)
*
*
* #throws NoSuchElementException if E not part of the set
* #param elem a element of the set
* #return a ListIterator - doesn't support nextIndex() or previousIndex()
*/
public ListIterator<E> from(E elem) {
Node e = m.get(elem);
if (e == null) {
throw new NoSuchElementException("the given element isn't part of the set");
}
return new LinkedKeyIterator(e);
}
#Override
public ListIterator<E> iterator() {
return new LinkedKeyIterator();
}
/**
* Returns true if the value target was added before (exclusive) limitElem
* in insertion order.
*
* If target or limit are not present on the set this method returns false
*
* #param limitElem a E that may be a element of the set or not.
* #return if target was added before limit (can be reset by removing and
* re-adding the target, that changes iteration order).
*/
public boolean containsBefore(E target, E limitElem) {
if (isEmpty()) {
return false;
}
Integer targetN = m.get(target).relativeLocation;
Integer highN = m.get(limitElem).relativeLocation;
return targetN != null && highN != null && targetN < highN;
}
/**
* Returns true if the value target was added after (exclusive) previousElem
* in insertion order.
*
* If target or previous are not present on the set this method returns
* false
*
* #param previousElem a E that may be a element of the set or not.
* #return if target was added before previous (can be reset by removing and
* re-adding the target, that changes iteration order).
*/
public boolean containsAfter(E target, E previousElem) {
if (isEmpty()) {
return false;
}
Integer targetN = m.get(target).relativeLocation;
Integer low = m.get(previousElem).relativeLocation;
return targetN != null && low != null && low < targetN;
}
#Override
public boolean add(E e) {
if (!m.containsKey(e)) {
Node n = new Node(e, monotonicallyIncreasing);
monotonicallyIncreasing += iteratorAddStep;
n.addBefore(head);//insertion order
m.put(e, n);
return true;
}
return false;
}
#Override
public int size() {
return m.size();
}
#Override
public boolean isEmpty() {
return m.isEmpty();
}
#Override
public boolean contains(Object o) {
return m.containsKey(o);
}
#Override
public Object[] toArray() {
Object[] result = new Object[size()];
int i = 0;
for (E e : this) {
result[i++] = e;
}
return result;
}
#Override
#SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
int size = size();
if (a.length < size) {
a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
}
int i = 0;
Object[] result = a;
for (E e : this) {
result[i++] = e;
}
if (a.length > size) {
//peculiar toArray contract where it doesn't care about the rest
a[size] = null;
}
return a;
}
#Override
public boolean remove(Object o) {
Node n = m.remove(o);
if (n != null) {
n.remove();
return true;
}
return false;
}
#Override
public boolean addAll(Collection<? extends E> c) {
boolean changed = false;
for (E e : c) {
changed |= add(e);
}
return changed;
}
#Override
public boolean containsAll(Collection<?> c) {
boolean all = true;
for (Object e : c) {
all &= m.containsKey(e);
}
return all;
}
#Override
public boolean retainAll(Collection<?> c) {
boolean changed = false;
Iterator<E> it = iterator();
while (it.hasNext()) {
E k = it.next();
if (!c.contains(k)) {
it.remove();
changed = true;
}
}
return changed;
}
#Override
public void clear() {
modCount++;
head.after = head.before = head;
m.clear();
}
#Override
public String toString() {
return m.keySet().toString();
}
//linkedlist node class
protected final class Node {
Node before, after;
int relativeLocation;
//needed for map removal during iteration
E key;
private void remove() {
before.after = after;
after.before = before;
modCount++;
}
private void addBefore(Node existingEntry) {
after = existingEntry;
before = existingEntry.before;
before.after = this;
after.before = this;
modCount++;
}
//head const
public Node() {
after = before = this;
relativeLocation = 0;
}
public Node(E key, int value) {
this.key = key;
this.relativeLocation = value;
}
}
protected class LinkedKeyIterator implements ListIterator<E> {
Node nextEntry;
Node lastReturned;
int expectedModCount = modCount;
public LinkedKeyIterator() {
nextEntry = head.after;
}
public LinkedKeyIterator(Node startAt) {
nextEntry = startAt;
}
public boolean hasPrevious() {
return nextEntry.before != head;
}
public boolean hasNext() {
return nextEntry != head;
}
public E next() {
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (nextEntry == head) {
throw new NoSuchElementException();
}
Node e = lastReturned = nextEntry;
nextEntry = e.after;
return e.key;
}
public E previous() {
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (nextEntry.before == head) {
throw new NoSuchElementException();
}
Node e = lastReturned = nextEntry.before;
nextEntry = e;
return e.key;
}
public void remove() {
if (lastReturned == null) {
throw new IllegalStateException();
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
m.remove(lastReturned.key);
nextEntry = lastReturned.after;
lastReturned.remove();
lastReturned = null;
expectedModCount = modCount;
}
#Override
public void set(E e) {
if (lastReturned == null) {
throw new IllegalStateException();
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (lastReturned.key.equals(e)) {
return;
}
//remove mapping for key since we are changing it
m.remove(lastReturned.key);
//put in the new one
lastReturned.key = e;
Node previousKeyOwner = m.put(e, lastReturned);
if (previousKeyOwner != null) {
//as it is a list mutation call, guard against stale iterator
if(nextEntry == previousKeyOwner){
nextEntry = nextEntry.after;
}
previousKeyOwner.remove();
}
//from m.remove and m.put, may help with 2 concurrent iterators on this instance
//this method may not change modCount if previousKeyOwner is null
expectedModCount = ++modCount;
}
#Override
public void add(E e) {
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
//calculate a good relative location, updating subsequent ones if needed
int candidateLoc = nextEntry.before.relativeLocation + 1;
//opsss, it's full
if (candidateLoc == nextEntry.relativeLocation) {
iteratorAddStep *= 1.6;
for (Node current = nextEntry; current != head; current = current.after) {
current.relativeLocation = current.relativeLocation + iteratorAddStep;
}
}
Node n = m.get(e);
if (n == null) {
n = new Node(e, candidateLoc);
m.put(e, n);
} else {
n.relativeLocation = candidateLoc;
//as it is a list mutation call, guard against stale iterator
if(nextEntry == n){
nextEntry = nextEntry.after;
}
n.remove();
}
n.addBefore(nextEntry);
expectedModCount = modCount;//add before changes modCount
}
#Override
public int nextIndex() {
throw new UnsupportedOperationException("Not supported yet.");
}
#Override
public int previousIndex() {
throw new UnsupportedOperationException("Not supported yet.");
}
}
}
Related
I got this assignment to create an equals method for doubly linked list. So far I got the code I posted below. It passes some of the tests, but not all. The failures do have the same expected value as the actual value, but I still get some AssertionErrors.
Ive been messing and trying to change things for quite some time now, but I cant seem to figure it out on my own. Nor can I find any good examples on the internet. I've tried using Eclipse to generate the equals method, but that too does not pass all the tests.
I know you do not give away free answers here, but could someone maybe point to the mistake in the code?
/**
* This method should return true iff the values of this list
* and that are identical and in the same order.
* #param that list to compare this to.
* #return true iff the values are identical and in the same order
*/
public boolean equals(Object that) {
if (that == null)
return false;
if (!(that instanceof DoublyLinkedList) )
return false;
DoublyLinkedList<E> other = (DoublyLinkedList<E>) that;
if (header == null&&other.header != null)
return false;
if (trailer == null&&other.trailer != null)
return false;
while (header.getNext() != trailer){
if (!(header.equals(other.header))){
return false;
}
header = header.getNext();
other.header = other.header.getNext();
}
return true;
}
Edit, per request the failed tests en DLL class:
public static class DoublyLinkedList<E> {
private Node<E> header;
private Node<E> trailer;
/**
* Constructor that creates an empty DLL
*/
public DoublyLinkedList() {
this.header = new Node<>(null, null, null);
this.trailer = new Node<>(null, header, null);
this.header.setNext(trailer);
}
/**
* #return if the list is empty.
*/
public boolean isEmpty() {
return this.header.getNext() == this.trailer;
}
/**
* #return the first element of the list.
*/
public E getFirst() {
if (isEmpty()) return null;
return this.header.getNext().getElement();
}
/**
* #return the last element of the list.
*/
public E getLast() {
if (isEmpty()) return null;
return this.trailer.getPrevious().getElement();
}
/**
* Adds a new Node to the beginning of the list,
* containing the specified value.
* #param value for the new first node to hold.
*/
public void addFirst(E element) {
Node<E> newNode = new Node<>(element, header, header.getNext());
header.getNext().setPrevious(newNode);
header.setNext(newNode);
}
/**
* This method should return true iff the values of this list
* and that are identical and in the same order.
* #param that list to compare this to.
* #return true iff the values are identical and in the same order
*/
public boolean equals(Object that) {
if (that == null)
return false;
if (!(that instanceof DoublyLinkedList) )
return false;
DoublyLinkedList<E> other = (DoublyLinkedList<E>) that;
if (header == null&&other.header != null)
return false;
if (trailer == null&&other.trailer != null)
return false;
while (header.getNext() != trailer){
if (!(header.equals(other.header))){
return false;
}
header = header.getNext();
other.header = other.header.getNext();
}
return true;
}
/**
* Simple toString for testing purposes. Please note that solutions that use the
* .toString() to implement the .equals() method will be rejected.
*/
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("DoublyLinkedList<");
Node<E> finger = header.getNext();
while (finger != trailer) {
sb.append(finger.toString());
if (finger.getNext() != trailer) {
sb.append("-");
}
finger = finger.getNext();
}
sb.append(">");
return sb.toString();
}
}
And the tests:
#Test
public void testEqualsCopy() {
Solution.DoublyLinkedList<Integer> dll1 = createDLL(2);
Solution.DoublyLinkedList<Integer> dll2 = createDLL(2);
assertEquals(dll1, dll2);
}
#Test
// Both lists contain only the entry 42.
public void testTwoEqualLists() {
Solution.DoublyLinkedList<Integer> dll1 = new Solution.DoublyLinkedList<>();
Solution.DoublyLinkedList<Integer> dll2 = new Solution.DoublyLinkedList<>();
dll1.addFirst(42);
dll2.addFirst(42);
assertEquals(dll1, dll2);
}
and the errors:
testEqualsCopy(UTest) failed: 'java.lang.AssertionError: expected: Solution$DoublyLinkedList<DoublyLinkedList<1-0>> but was: Solution$DoublyLinkedList<DoublyLinkedList<1-0>>'
testTwoEqualLists(UTest) failed: 'java.lang.AssertionError: expected: Solution$DoublyLinkedList<DoublyLinkedList<42>> but was: Solution$DoublyLinkedList<DoublyLinkedList<42>>'
Since, there's quite a gap between what I think a doubly linked list should look like and what you have, I would like to add my sample implementation instead. It does away with the dummy header and trailer nodes which IMHO aren't required at all.
public class DoublyLinkedList<E> {
private Node<E> header;
private Node<E> trailer;
/**
* #return if the list is empty.
*/
public boolean isEmpty() {
return header == null;
}
/**
* #return the first element of the list.
*/
public E getFirst() {
return header != null ? header.getElement() : null;
}
/**
* #return the last element of the list.
*/
public E getLast() {
return trailer != null ? trailer.getElement() : null;
}
/**
* Adds a new Node to the beginning of the list,
* containing the specified value.
* #param value for the new first node to hold.
*/
public void addFirst(E element) {
Node<E> newNode = new Node<E>(element, null, header);
header = newNode;
if (trailer == null) {
trailer = newNode;
}
}
/**
* This method should return true if the values of this list and that are
* identical and in the same order.
*
* #param that
* list to compare this to.
* #return true if the values are identical and in the same order
*/
#SuppressWarnings("unchecked")
public boolean equals(Object that) {
if (!(that instanceof DoublyLinkedList))
return false;
DoublyLinkedList<E> other = (DoublyLinkedList<E>) that;
// if lists are empty
if (header == null) {
return other.header == null ? true : false;
}
if (!header.equals(other.header))
return false;
// Just one element
if (header == trailer) {
return true;
}
if (!trailer.equals(other.trailer))
return false;
Node<E> thisNode = header;
Node<E> otherNode = other.header;
while (thisNode.getNext() != trailer) {
thisNode = thisNode.getNext();
otherNode = otherNode.getNext();
if (!(thisNode.equals(otherNode))) {
return false;
}
}
return true;
}
/**
* Simple toString for testing purposes. Please note that solutions that use the
* .toString() to implement the .equals() method will be rejected.
*/
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("DoublyLinkedList<");
Node<E> finger = header;
while (finger != null) {
sb.append(finger.toString());
if (finger.getNext() != null) {
sb.append("-");
}
finger = finger.getNext();
}
sb.append(">");
return sb.toString();
}
}
Here's what my Node class looks like. Not many changes here.
public class Node<E> {
private E element;
private Node<E> previous;
private Node<E> next;
public Node<E> getPrevious() {
return previous;
}
public Node<E> getNext() {
return next;
}
public E getElement() {
return element;
}
public Node(E element, Node<E> previous, Node<E> next) {
this.element = element;
this.previous = previous;
this.next = next;
}
#Override
#SuppressWarnings("unchecked")
public boolean equals(Object that) {
if (!(that instanceof Node)) {
return false;
}
Node<E> other = (Node<E>) that;
if (element == null) {
return other.element == null ? true : false;
}
return element.equals(other.element);
}
#Override
public String toString() {
return element.toString();
}
}
Here's the code I used to test my implementation.
DoublyLinkedList<Integer> dll1 = new DoublyLinkedList<Integer>();
dll1.addFirst(100);
dll1.addFirst(200);
DoublyLinkedList<Integer> dll2 = new DoublyLinkedList<Integer>();
dll2.addFirst(100);
dll2.addFirst(200);
DoublyLinkedList<Integer> dll3 = new DoublyLinkedList<Integer>();
dll3.addFirst(42);
DoublyLinkedList<String> blankList1 = new DoublyLinkedList<String>();
DoublyLinkedList<String> blankList2 = new DoublyLinkedList<String>();
if (blankList1.equals(blankList2)) {
System.out.println(blankList1 + " = " + blankList2);
}
if (!dll1.equals(dll3)) {
System.out.println(dll1 + " != " + dll3);
}
if (dll1.equals(dll2)) {
System.out.println(dll1 + " = " + dll2);
}
Output :
DoublyLinkedList<> = DoublyLinkedList<>
DoublyLinkedList<200-100> != DoublyLinkedList<42>
DoublyLinkedList<200-100> = DoublyLinkedList<200-100>
So I've been tasked to create a method to remove an element from a MultiSet. I've been trying for a while, but sadly in vain. My code is as follows:
import java.util.*;
public class MultiSet<E> extends AbstractCollection<E> {
private HashMap<E, Integer> elements;
private int noOfElems;
public MultiSet() {
elements = new HashMap<E, Integer>();
noOfElems= 0;
}
public MultiSet(Collection<E> c) {
this();
addAll(c);
}
public int size() {
return noOfElems;
}
public Iterator<E> iterator() {
return new Iterator<E>() {
Iterator<E> iterator = elements.keySet().iterator();
int elemsLeft = 0;
E thisElem = null;
public boolean hasNext() {
return iterator.hasNext();
}
public E next() {
if (elemsLeft == 0) {
thisElem = iterator.next();
elemsLeft = elements.get(thisElem);
}
elemsLeft -= elemsLeft;
return null;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public boolean add(E e) {
Integer i = elements.get(e);
if(i == null) {
i = 1;
} else {
i += 1;
}
elements.put(e, i);
noOfElems++;
return true;
}
public String toString() {
return elements.toString();
}
public int hashCode() {
return elements.hashCode();
}
public boolean equals(MultiSet<E> other) {
if (this == other) {
return true;
}
if (other == null) {
return false;
}
if (this.getClass() != other.getClass()) {
return false;
}
MultiSet<?> obj = (MultiSet<?>) other;
return obj.elements.equals(elements);
}
public boolean remove(Object o) {
}
}
And I want to implement the remove method. Anything that will help me, even a few pointers on where to start, will be greatly appreciated. Thanks! (also, comments on the rest of my code will also be appreciated)
This multiset just stores the elements as hash keys mapped to a count of the number of occurrences. To remove all instances of an element, just delete the key:
public void remove_all(E e) {
elements.remove(e);
}
If you need to remove only one instance, then decrement the count unless it's already a 1. In that case, remove the key.
public void remove(E e) {
Integer i = elements.get(e);
if (i != null) {
if (i == 1) {
elements.remove(e);
} else {
elements.put(e, i - 1);
}
}
}
BTW it's a bit hard to believe this is your code. If you understand enough to write the methods you've already written, how could you not know even where to start on remove?
I've looked at a bunch of the questions in this area and can't find one that solves my problem specifically.
Basically, this is a homework assigment where I have a linked list with nodes, which hold an element. The node class (LinearNode) and the element class (Golfer) both implement Comparable and override the compareTo method. However, the runtime fails trying to add a new node to the list (first node is added fine) with a class cast exception: supersenior.LinearNode cannot be cast to supersenior.Golfer. I don't know why it's trying to take the node and compare it to an element of the node to be compared...i've even tried explicitly casting. The following error is observed:
Exception in thread "main" java.lang.ClassCastException: supersenior.LinearNode cannot be cast to supersenior.Golfer
at supersenior.Golfer.compareTo(Golfer.java:12)
at supersenior.LinearNode.compareTo(LinearNode.java:80)
at supersenior.LinearNode.compareTo(LinearNode.java:80)
at supersenior.LinkedList.add(LinkedList.java:254)
at supersenior.SuperSenior.main(SuperSenior.java:100)
Any help would be greatly appreciated. Thanks!
LinkedList class:
package supersenior;
import supersenior.exceptions.*;
import java.util.*;
public class LinkedList<T> implements OrderedListADT<T>, Iterable<T>
{
protected int count;
protected LinearNode<T> head, tail;
/**
* Creates an empty list.
*/
public LinkedList()
{
count = 0;
head = tail = null;
}
public T removeFirst() throws EmptyCollectionException
{
if (isEmpty())
throw new EmptyCollectionException ("List");
LinearNode<T> result = head;
head = head.getNext();
if (head == null)
tail = null;
count--;
return result.getElement();
}
public T removeLast() throws EmptyCollectionException
{
if (isEmpty())
throw new EmptyCollectionException ("List");
LinearNode<T> previous = null;
LinearNode<T> current = head;
while (current.getNext() != null)
{
previous = current;
current = current.getNext();
}
LinearNode<T> result = tail;
tail = previous;
if (tail == null)
head = null;
else
tail.setNext(null);
count--;
return result.getElement();
}
public T remove (T targetElement) throws EmptyCollectionException,
ElementNotFoundException
{
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 ("List");
if (size() == 1)
head = tail = null;
else if (current.equals (head))
head = current.getNext();
else if (current.equals (tail))
{
tail = previous;
tail.setNext(null);
}
else
previous.setNext(current.getNext());
count--;
return current.getElement();
}
public boolean contains (T targetElement) throws
EmptyCollectionException
{
if (isEmpty())
throw new EmptyCollectionException ("List");
boolean found = false;
Object result;
LinearNode<T> current = head;
while (current != null && !found)
if (targetElement.equals (current.getElement()))
found = true;
else
current = current.getNext();
return found;
}
public boolean isEmpty()
{
return (count == 0);
}
public int size()
{
return count;
}
public String toString()
{
LinearNode<T> current = head;
String result = "";
while (current != null)
{
result = result + (current.getElement()).toString() + "\n";
current = current.getNext();
}
return result;
}
public Iterator<T> iterator()
{
return new LinkedIterator<T>(head, count);
}
public T first()
{
return head.getElement();
}
public T last()
{
return tail.getElement();
}
#Override
public void add (T element)
{
LinearNode<T>node = new LinearNode<T>();
node.setElement(element);
if(isEmpty())
{
head = node;
if(tail == null)
tail = head;
//node.setNext(head);
//head.setPrevious(node);
//head.setElement((T) node);
count++;
}
else
{
for(LinearNode<T> current = head; current.getNext() != null; current = current.getNext())
if(node.compareTo((T) current) >= 0)
{
current.setPrevious(current);
current.setNext(current);
}
else
{
current.setPrevious(node);
}
tail.setNext(node);
}
}
}
LinearNode class:
package supersenior;
public class LinearNode<E> implements Comparable<E>
{
private LinearNode<E> next, previous;
public E element;
public LinearNode()
{
next = null;
element = null;
}
public LinearNode (E elem)
{
next = null;
element = elem;
}
public LinearNode<E> getNext()
{
return next;
}
public void setNext (LinearNode<E> node)
{
next = node;
}
public E getElement()
{
return element;
}
public void setElement (E elem)
{
element = elem;
}
#Override
public int compareTo(E otherElement) {
return ((Comparable<E>) this.element).compareTo(otherElement);
}
public LinearNode<E> getPrevious()
{
return previous;
}
public void setPrevious (LinearNode<E> node)
{
previous = node;
}
}
The element class (Golfer):
package supersenior;
public class Golfer implements Comparable<Golfer>{
Golfer imaGolfer;
String name;
int tourneys;
int winnings;
double avg;
public Golfer(String attr[]){
this.name = attr[0];
this.tourneys = Integer.parseInt(attr[1]);
this.winnings = Integer.parseInt(attr[2]);
this.avg = findAvg(winnings, tourneys);
}
private double findAvg(int winnings, int tourneys){
double a = winnings/tourneys;
return a;
}
#Override
public String toString(){
return "Name: " + name + " Tourneys: " + tourneys + " Winnings: " + winnings + " Average: " + avg;
}
#Override
public int compareTo(Golfer golfer) {
if(this.avg <= golfer.avg)
return 1;
if(this.avg == golfer.avg)
return 0;
else
return -1;
}
}
The problem is that you're mixing what's being compared. You're trying to compare the LinearNode object (which holds an E) to an actual E. LinearNode<E> shouldn't implement Comparable<E>; if anything, it might implement Comparable<LinearNode<E>>, and the type parameter should probably be E extends Comparable<E>.
If you want to order LinearNodes based on the ordering of their underlying elements, you should use something like this:
// in LinearNode
public int compareTo(LinearNode<E> otherNode) {
return this.element.compareTo(otherNode.element);
}
(Note that the Java sorted collections don't require elements to implement Comparable, since you can provide a custom Comparator for any of them, but in the case of this assignment it's probably fine to require that E extends Comparable<E>.)
(Note 2: If you're using Generics, any cast, such as your (Comparable<E>), is a red flag; the purpose of the Generics system is to eliminate the need for most explicit casts.)
I'm having a problem with trying the logic and trying to write a min and additionMerge function and their recursive versions of the function that takes at least one list as an argument (the first node of the list). This will be a private helper function that is called by a wrapper function that is a member function of the LinkedList class.
public class LinkedList {
private static class ListNode {
public int firstItem;
public ListNode restOfList;
}
private ListNode first;
/**
* Create an empty list.
*/
public LinkedList() {
first = null;
}
public LinkedList(int n) {
first = countDown(n);
}
public LinkedList(String s) {
String[] temp = s.split(",");
for (int i = temp.length-1; i >= 0; i--) {
first = insertAtFront(first, Integer.parseInt(temp[i]));
}
}
public int length() {
return length(first);
}
private static int length(ListNode list) {
if (list == null) {
return 0;
}
int temp = length(list.restOfList);
return temp + 1;
}
public boolean contains(int value) {
return contains(first, value);
}
private static boolean contains(ListNode list, int value) {
if (list == null) {
return false;
}
if (list.firstItem == value) {
return true;
}
return contains(list.restOfList, value);
}
public int sum() {
return sum(first);
}
private static int sum(ListNode list) {
if (list == null) {
return 0;
}
return sum(list.restOfList) + list.firstItem;
}
public int count(int target) {
return count(first, target);
}
private static int count(ListNode list, int target) {
if (list == null) {
return 0;
}
int temp = count(list.restOfList, target);
if (list.firstItem == target) {
temp++;
}
return temp;
}
public void replace(int oldValue, int newValue) {
replace(first, oldValue, newValue);
}
private static void replace(ListNode list, int oldValue, int newValue) {
if (list == null) {
return;
}
replace(list.restOfList, oldValue, newValue);
if (list.firstItem == oldValue) {
list.firstItem = newValue;
}
}
public void insertAtFront(int n) {
first = insertAtFront(first, n);
}
private static ListNode insertAtFront(ListNode list, int n) {
ListNode answer = new ListNode();
answer.firstItem = n;
answer.restOfList = list;
return answer;
}
private static ListNode countDown(int n) {
if (n == 1) {
ListNode answer = new ListNode();
answer.firstItem = 1;
answer.restOfList = null;
return answer;
}
ListNode temp = countDown(n - 1);
ListNode answer = insertAtFront(temp, n);
return answer;
}
public void insertAtBack(int item) {
first = insertAtBack(first, item);
}
private static ListNode insertAtBack(ListNode list, int item) {
if (list == null) {
ListNode answer = new ListNode();
answer.firstItem = item;
answer.restOfList = null;
return answer;
}
//List answer = new ListNode();
//answer.firstItem = list.firstItem;
ListNode temp = insertAtBack(list.restOfList, item);
//answer.restOfList = temp;
list.restOfList = temp;
return list;
}
public void concatenate(LinkedList otherList) {
this.first = concatenate(this.first, otherList.first);
}
private static ListNode concatenate(ListNode list1, ListNode list2) {
if (list1 == null) {
return list2;
}
ListNode temp = concatenate(list1.restOfList, list2);
list1.restOfList = temp;
return list1;
}
public void filter(int item) {
first = filter(first, item);
}
#Override
public String toString() {
if (first == null) {
return "";
}
StringBuilder sb = new StringBuilder(256);
sb.append(first.firstItem);
for (ListNode current = first.restOfList;
current != null;
current = current.restOfList) {
sb.append(',');
sb.append(current.firstItem);
}
return sb.toString();
}
private static ListNode filter(ListNode list, int item) {
if (list == null) {
return null;
}
ListNode temp = filter(list.restOfList, item);
if (list.firstItem == item) {
return temp;
}
list.restOfList = temp;
return list;
}
public int min() throws RuntimeException {
if (first == null)
throw new RuntimeException("List is Empty");
else
return min();
}
// * A private recursive helper function that returns the minimum item in a
* list whose first node is the argument list.
private static int min(ListNode list) throws RuntimeException {
if (list == null) {
return 0;
}
}
public void additionMerge(LinkedList l2) {
}
* Every node in the list that begins with node
* node1 is increased by the ammount of the corresponding
* node in the list that begins with node node2.
* If one list is longer than the other, the missing nodes
* in the shorter list are assumed to be 0.
private static ListNode additionMerge(ListNode node1, ListNode node2) {
if (list == null) {
return null;
}
}
}
If this is not homework, then my advice is:
Don't write your own LinkedList class. Use the existing out, and add the extra functionality either as a helper class or by extending the existing class.
If you do decide to implement your own linked list class, then you should beware of using recursion. Recursion gives a neat soltion, but there is a major drawback with recursion in Java. The JVM does not do tail call optimization, so a recusive algorithm that recurses deeply (e.g. recursively traversing a long list) is liable to cause a StackOverflowError.
Is there a way to iterate over Java SparseArray (for Android) ? I used sparsearray to easily get values by index. I could not find one.
Seems I found the solution. I hadn't properly noticed the keyAt(index) function.
So I'll go with something like this:
for(int i = 0; i < sparseArray.size(); i++) {
int key = sparseArray.keyAt(i);
// get the object by the key.
Object obj = sparseArray.get(key);
}
If you don't care about the keys, then valueAt(int) can be used to while iterating through the sparse array to access the values directly.
for(int i = 0, nsize = sparseArray.size(); i < nsize; i++) {
Object obj = sparseArray.valueAt(i);
}
Ooor you just create your own ListIterator:
public final class SparseArrayIterator<E> implements ListIterator<E> {
private final SparseArray<E> array;
private int cursor;
private boolean cursorNowhere;
/**
* #param array
* to iterate over.
* #return A ListIterator on the elements of the SparseArray. The elements
* are iterated in the same order as they occur in the SparseArray.
* {#link #nextIndex()} and {#link #previousIndex()} return a
* SparseArray key, not an index! To get the index, call
* {#link android.util.SparseArray#indexOfKey(int)}.
*/
public static <E> ListIterator<E> iterate(SparseArray<E> array) {
return iterateAt(array, -1);
}
/**
* #param array
* to iterate over.
* #param key
* to start the iteration at. {#link android.util.SparseArray#indexOfKey(int)}
* < 0 results in the same call as {#link #iterate(android.util.SparseArray)}.
* #return A ListIterator on the elements of the SparseArray. The elements
* are iterated in the same order as they occur in the SparseArray.
* {#link #nextIndex()} and {#link #previousIndex()} return a
* SparseArray key, not an index! To get the index, call
* {#link android.util.SparseArray#indexOfKey(int)}.
*/
public static <E> ListIterator<E> iterateAtKey(SparseArray<E> array, int key) {
return iterateAt(array, array.indexOfKey(key));
}
/**
* #param array
* to iterate over.
* #param location
* to start the iteration at. Value < 0 results in the same call
* as {#link #iterate(android.util.SparseArray)}. Value >
* {#link android.util.SparseArray#size()} set to that size.
* #return A ListIterator on the elements of the SparseArray. The elements
* are iterated in the same order as they occur in the SparseArray.
* {#link #nextIndex()} and {#link #previousIndex()} return a
* SparseArray key, not an index! To get the index, call
* {#link android.util.SparseArray#indexOfKey(int)}.
*/
public static <E> ListIterator<E> iterateAt(SparseArray<E> array, int location) {
return new SparseArrayIterator<E>(array, location);
}
private SparseArrayIterator(SparseArray<E> array, int location) {
this.array = array;
if (location < 0) {
cursor = -1;
cursorNowhere = true;
} else if (location < array.size()) {
cursor = location;
cursorNowhere = false;
} else {
cursor = array.size() - 1;
cursorNowhere = true;
}
}
#Override
public boolean hasNext() {
return cursor < array.size() - 1;
}
#Override
public boolean hasPrevious() {
return cursorNowhere && cursor >= 0 || cursor > 0;
}
#Override
public int nextIndex() {
if (hasNext()) {
return array.keyAt(cursor + 1);
} else {
throw new NoSuchElementException();
}
}
#Override
public int previousIndex() {
if (hasPrevious()) {
if (cursorNowhere) {
return array.keyAt(cursor);
} else {
return array.keyAt(cursor - 1);
}
} else {
throw new NoSuchElementException();
}
}
#Override
public E next() {
if (hasNext()) {
if (cursorNowhere) {
cursorNowhere = false;
}
cursor++;
return array.valueAt(cursor);
} else {
throw new NoSuchElementException();
}
}
#Override
public E previous() {
if (hasPrevious()) {
if (cursorNowhere) {
cursorNowhere = false;
} else {
cursor--;
}
return array.valueAt(cursor);
} else {
throw new NoSuchElementException();
}
}
#Override
public void add(E object) {
throw new UnsupportedOperationException();
}
#Override
public void remove() {
if (!cursorNowhere) {
array.remove(array.keyAt(cursor));
cursorNowhere = true;
cursor--;
} else {
throw new IllegalStateException();
}
}
#Override
public void set(E object) {
if (!cursorNowhere) {
array.setValueAt(cursor, object);
} else {
throw new IllegalStateException();
}
}
}
For whoever is using Kotlin, honestly the by far easiest way to iterate over a SparseArray is: Use the Kotlin extension from Anko or Android KTX! (credit to Yazazzello for pointing out Android KTX)
Simply call forEach { i, item -> }
Simple as Pie. Just make sure you fetch array size before actually performing the loop.
for(int i = 0, arraySize= mySparseArray.size(); i < arraySize; i++) {
Object obj = mySparseArray.get(/* int key = */ mySparseArray.keyAt(i));
}
Hope this helps.
For removing all the elements from SparseArray using the above looping leads to Exception.
To avoid this Follow the below code to remove all the elements from SparseArray using normal loops
private void getValues(){
for(int i=0; i<sparseArray.size(); i++){
int key = sparseArray.keyAt(i);
Log.d("Element at "+key, " is "+sparseArray.get(key));
sparseArray.remove(key);
i=-1;
}
}
Here is simple Iterator<T> and Iterable<T> implementations for SparseArray<T>:
public class SparseArrayIterator<T> implements Iterator<T> {
private final SparseArray<T> array;
private int index;
public SparseArrayIterator(SparseArray<T> array) {
this.array = array;
}
#Override
public boolean hasNext() {
return array.size() > index;
}
#Override
public T next() {
return array.valueAt(index++);
}
#Override
public void remove() {
array.removeAt(index);
}
}
public class SparseArrayIterable<T> implements Iterable<T> {
private final SparseArray<T> sparseArray;
public SparseArrayIterable(SparseArray<T> sparseArray) {
this.sparseArray = sparseArray;
}
#Override
public Iterator<T> iterator() {
return new SparseArrayIterator<>(sparseArray);
}
}
If you want to iterate not only a value but also a key:
public class SparseKeyValue<T> {
private final int key;
private final T value;
public SparseKeyValue(int key, T value) {
this.key = key;
this.value = value;
}
public int getKey() {
return key;
}
public T getValue() {
return value;
}
}
public class SparseArrayKeyValueIterator<T> implements Iterator<SparseKeyValue<T>> {
private final SparseArray<T> array;
private int index;
public SparseArrayKeyValueIterator(SparseArray<T> array) {
this.array = array;
}
#Override
public boolean hasNext() {
return array.size() > index;
}
#Override
public SparseKeyValue<T> next() {
SparseKeyValue<T> keyValue = new SparseKeyValue<>(array.keyAt(index), array.valueAt(index));
index++;
return keyValue;
}
#Override
public void remove() {
array.removeAt(index);
}
}
public class SparseArrayKeyValueIterable<T> implements Iterable<SparseKeyValue<T>> {
private final SparseArray<T> sparseArray;
public SparseArrayKeyValueIterable(SparseArray<T> sparseArray) {
this.sparseArray = sparseArray;
}
#Override
public Iterator<SparseKeyValue<T>> iterator() {
return new SparseArrayKeyValueIterator<T>(sparseArray);
}
}
It's useful to create utility methods that return Iterable<T> and Iterable<SparseKeyValue<T>>:
public abstract class SparseArrayUtils {
public static <T> Iterable<SparseKeyValue<T>> keyValueIterable(SparseArray<T> sparseArray) {
return new SparseArrayKeyValueIterable<>(sparseArray);
}
public static <T> Iterable<T> iterable(SparseArray<T> sparseArray) {
return new SparseArrayIterable<>(sparseArray);
}
}
Now you can iterate SparseArray<T>:
SparseArray<String> a = ...;
for (String s: SparseArrayUtils.iterable(a)) {
// ...
}
for (SparseKeyValue<String> s: SparseArrayUtils.keyValueIterable(a)) {
// ...
}
If you use Kotlin, you can use extension functions as such, for example:
fun <T> LongSparseArray<T>.valuesIterator(): Iterator<T> {
val nSize = this.size()
return object : Iterator<T> {
var i = 0
override fun hasNext(): Boolean = i < nSize
override fun next(): T = valueAt(i++)
}
}
fun <T> LongSparseArray<T>.keysIterator(): Iterator<Long> {
val nSize = this.size()
return object : Iterator<Long> {
var i = 0
override fun hasNext(): Boolean = i < nSize
override fun next(): Long = keyAt(i++)
}
}
fun <T> LongSparseArray<T>.entriesIterator(): Iterator<Pair<Long, T>> {
val nSize = this.size()
return object : Iterator<Pair<Long, T>> {
var i = 0
override fun hasNext(): Boolean = i < nSize
override fun next() = Pair(keyAt(i), valueAt(i++))
}
}
You can also convert to a list, if you wish. Example:
sparseArray.keysIterator().asSequence().toList()
I think it might even be safe to delete items using remove on the LongSparseArray itself (not on the iterator), as it is in ascending order.
EDIT: Seems there is even an easier way, by using collection-ktx (example here) . It's implemented in a very similar way to what I wrote, actally.
Gradle requires this:
implementation 'androidx.core:core-ktx:#'
implementation 'androidx.collection:collection-ktx:#'
Here's the usage for LongSparseArray :
val sparse= LongSparseArray<String>()
for (key in sparse.keyIterator()) {
}
for (value in sparse.valueIterator()) {
}
sparse.forEach { key, value ->
}
And for those that use Java, you can use LongSparseArrayKt.keyIterator , LongSparseArrayKt.valueIterator and LongSparseArrayKt.forEach , for example. Same for the other cases.
The answer is no because SparseArray doesn't provide it. As pst put it, this thing doesn't provide any interfaces.
You could loop from 0 - size() and skip values that return null, but that is about it.
As I state in my comment, if you need to iterate use a Map instead of a SparseArray. For example, use a TreeMap which iterates in order by the key.
TreeMap<Integer, MyType>
The accepted answer has some holes in it. The beauty of the SparseArray is that it allows gaps in the indeces. So, we could have two maps like so, in a SparseArray...
(0,true)
(250,true)
Notice the size here would be 2. If we iterate over size, we will only get values for the values mapped to index 0 and index 1. So the mapping with a key of 250 is not accessed.
for(int i = 0; i < sparseArray.size(); i++) {
int key = sparseArray.keyAt(i);
// get the object by the key.
Object obj = sparseArray.get(key);
}
The best way to do this is to iterate over the size of your data set, then check those indeces with a get() on the array. Here is an example with an adapter where I am allowing batch delete of items.
for (int index = 0; index < mAdapter.getItemCount(); index++) {
if (toDelete.get(index) == true) {
long idOfItemToDelete = (allItems.get(index).getId());
mDbManager.markItemForDeletion(idOfItemToDelete);
}
}
I think ideally the SparseArray family would have a getKeys() method, but alas it does not.