Why doesn't ArrayDeque implement List? - java

I currently want a data structure that acts like a Deque with indexing.
So, it should have O(1) addition and removal of elements at the front and back, as well as O(1) access of elements based on the index. It is not that hard to imagine a setup that would work for this.
It seems like ArrayDeque would be a natural choice for this. However, ArrayDeque does not implement List. Since the underlying data structure is an array, is there a good reason that it does not allow indexing?
Also, on a more practical note, does anyone know of any library doing the thing I want. Apache Commons does not have one as far as I can see.

(edit, original answer was mostly wrong)
There's no good reason why this class doesn't have an indexing. I checked the source code. It runs exactly like I suggested above. Some of the other items might be harder to add within the List interface. But, simple get wouldn't be one of them.
You take an array of a given size depending on your usage. Then set the start position halfway into it. Then you track a variable for the head and the tail. As you iterate items you move the head back and tail forward expanding outward. If you reach need a value outside the range you modulo that value so .length is equal to 0, and -1 is equal to (.length -1) and you keep adding values until ((tail - head) > .length) at which point you build another array copying all the pieces to be coherent usually about twice the size. Then to index it, you take head +index to get the real index.
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ArrayDeque.java
Pretty sure the get is trivially akin to:
#Override
public E get(int index) {
int i = (head + index) & (elements.length - 1);
return elements[i];
}
Which seems like they should almost certainly have that. (See source code link for licensing info for the following).
import java.io.*;
import java.util.AbstractCollection;
import java.util.Arrays;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
public class ArrayDequeList<E> extends AbstractCollection<E> implements Deque<E>, Cloneable, Serializable, List<E>
{
private transient E[] elements;
private transient int head;
private transient int tail;
private static final int MIN_INITIAL_CAPACITY = 8;
private void allocateElements(int numElements) {
int initialCapacity = MIN_INITIAL_CAPACITY;
// Find the best power of two to hold elements.
// Tests "<=" because arrays aren't kept full.
if (numElements >= initialCapacity) {
initialCapacity = numElements;
initialCapacity |= (initialCapacity >>> 1);
initialCapacity |= (initialCapacity >>> 2);
initialCapacity |= (initialCapacity >>> 4);
initialCapacity |= (initialCapacity >>> 8);
initialCapacity |= (initialCapacity >>> 16);
initialCapacity++;
if (initialCapacity < 0) // Too many elements, must back off
initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
}
elements = (E[]) new Object[initialCapacity];
}
#Override
public boolean addAll(int index, #NonNull Collection<? extends E> c) {
return false;
}
#Override
public E get(int index) {
int i = (head + index) & (elements.length - 1);
return elements[i];
}
#Override
public E set(int index, E element) {
int i = (head + index) & (elements.length - 1);
E old = elements[i];
elements[i] = element;
return old;
}
#Override
public void add(int index, E element) {
throw new IllegalStateException("This one is hard to do.");
}
#Override
public E remove(int index) {
throw new IllegalStateException("This one is hard to do.");
}
#Override
public int indexOf(Object o) {
throw new IllegalStateException("This one's not that hard but pass..");
}
#Override
public int lastIndexOf(Object o) {
throw new IllegalStateException("This one's not that hard but pass..");
}
#Override
public ListIterator<E> listIterator() {
throw new IllegalStateException("Needs to write a new iterator..");
}
#NonNull
#Override
public ListIterator<E> listIterator(int index) {
throw new IllegalStateException("Needs to write a new iterator..");
}
#NonNull
#Override
public List<E> subList(int fromIndex, int toIndex) {
throw new IllegalStateException("Hm, not sure how this would work.");
}
private void doubleCapacity() {
assert head == tail;
int p = head;
int n = elements.length;
int r = n - p; // number of elements to the right of p
int newCapacity = n << 1;
if (newCapacity < 0)
throw new IllegalStateException("Sorry, deque too big");
Object[] a = new Object[newCapacity];
System.arraycopy(elements, p, a, 0, r);
System.arraycopy(elements, 0, a, r, p);
elements = (E[])a;
head = 0;
tail = n;
}
private <T> T[] copyElements(T[] a) {
if (head < tail) {
System.arraycopy(elements, head, a, 0, size());
} else if (head > tail) {
int headPortionLen = elements.length - head;
System.arraycopy(elements, head, a, 0, headPortionLen);
System.arraycopy(elements, 0, a, headPortionLen, tail);
}
return a;
}
public ArrayDequeList() {
elements = (E[]) new Object[16];
}
public ArrayDequeList(int numElements) {
allocateElements(numElements);
}
public ArrayDequeList(Collection<? extends E> c) {
allocateElements(c.size());
addAll(c);
}
public void addFirst(E e) {
if (e == null)
throw new NullPointerException();
elements[head = (head - 1) & (elements.length - 1)] = e;
if (head == tail)
doubleCapacity();
}
public void addLast(E e) {
if (e == null)
throw new NullPointerException();
elements[tail] = e;
if ( (tail = (tail + 1) & (elements.length - 1)) == head)
doubleCapacity();
}
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
public boolean offerLast(E e) {
addLast(e);
return true;
}
public E removeFirst() {
E x = pollFirst();
if (x == null)
throw new NoSuchElementException();
return x;
}
public E removeLast() {
E x = pollLast();
if (x == null)
throw new NoSuchElementException();
return x;
}
public E pollFirst() {
int h = head;
E result = elements[h]; // Element is null if deque empty
if (result == null)
return null;
elements[h] = null; // Must null out slot
head = (h + 1) & (elements.length - 1);
return result;
}
public E pollLast() {
int t = (tail - 1) & (elements.length - 1);
E result = elements[t];
if (result == null)
return null;
elements[t] = null;
tail = t;
return result;
}
public E getFirst() {
E x = elements[head];
if (x == null)
throw new NoSuchElementException();
return x;
}
public E getLast() {
E x = elements[(tail - 1) & (elements.length - 1)];
if (x == null)
throw new NoSuchElementException();
return x;
}
public E peekFirst() {
return elements[head]; // elements[head] is null if deque empty
}
public E peekLast() {
return elements[(tail - 1) & (elements.length - 1)];
}
public boolean removeFirstOccurrence(Object o) {
if (o == null)
return false;
int mask = elements.length - 1;
int i = head;
E x;
while ( (x = elements[i]) != null) {
if (o.equals(x)) {
delete(i);
return true;
}
i = (i + 1) & mask;
}
return false;
}
public boolean removeLastOccurrence(Object o) {
if (o == null)
return false;
int mask = elements.length - 1;
int i = (tail - 1) & mask;
E x;
while ( (x = elements[i]) != null) {
if (o.equals(x)) {
delete(i);
return true;
}
i = (i - 1) & mask;
}
return false;
}
public boolean add(E e) {
addLast(e);
return true;
}
public boolean offer(E e) {
return offerLast(e);
}
public E remove() {
return removeFirst();
}
public E poll() {
return pollFirst();
}
public E element() {
return getFirst();
}
public E peek() {
return peekFirst();
}
public void push(E e) {
addFirst(e);
}
public E pop() {
return removeFirst();
}
private void checkInvariants() {
assert elements[tail] == null;
assert head == tail ? elements[head] == null :
(elements[head] != null &&
elements[(tail - 1) & (elements.length - 1)] != null);
assert elements[(head - 1) & (elements.length - 1)] == null;
}
private boolean delete(int i) {
checkInvariants();
final E[] elements = this.elements;
final int mask = elements.length - 1;
final int h = head;
final int t = tail;
final int front = (i - h) & mask;
final int back = (t - i) & mask;
// Invariant: head <= i < tail mod circularity
if (front >= ((t - h) & mask))
throw new ConcurrentModificationException();
// Optimize for least element motion
if (front < back) {
if (h <= i) {
System.arraycopy(elements, h, elements, h + 1, front);
} else { // Wrap around
System.arraycopy(elements, 0, elements, 1, i);
elements[0] = elements[mask];
System.arraycopy(elements, h, elements, h + 1, mask - h);
}
elements[h] = null;
head = (h + 1) & mask;
return false;
} else {
if (i < t) { // Copy the null tail as well
System.arraycopy(elements, i + 1, elements, i, back);
tail = t - 1;
} else { // Wrap around
System.arraycopy(elements, i + 1, elements, i, mask - i);
elements[mask] = elements[0];
System.arraycopy(elements, 1, elements, 0, t);
tail = (t - 1) & mask;
}
return true;
}
}
public int size() {
return (tail - head) & (elements.length - 1);
}
public boolean isEmpty() {
return head == tail;
}
public Iterator<E> iterator() {
return new DeqIterator();
}
public Iterator<E> descendingIterator() {
return new DescendingIterator();
}
private class DeqIterator implements Iterator<E> {
private int cursor = head;
private int fence = tail;
private int lastRet = -1;
public boolean hasNext() {
return cursor != fence;
}
public E next() {
if (cursor == fence)
throw new NoSuchElementException();
E result = elements[cursor];
// This check doesn't catch all possible comodifications,
// but does catch the ones that corrupt traversal
if (tail != fence || result == null)
throw new ConcurrentModificationException();
lastRet = cursor;
cursor = (cursor + 1) & (elements.length - 1);
return result;
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
if (delete(lastRet)) { // if left-shifted, undo increment in next()
cursor = (cursor - 1) & (elements.length - 1);
fence = tail;
}
lastRet = -1;
}
}
private class DescendingIterator implements Iterator<E> {
private int cursor = tail;
private int fence = head;
private int lastRet = -1;
public boolean hasNext() {
return cursor != fence;
}
public E next() {
if (cursor == fence)
throw new NoSuchElementException();
cursor = (cursor - 1) & (elements.length - 1);
E result = elements[cursor];
if (head != fence || result == null)
throw new ConcurrentModificationException();
lastRet = cursor;
return result;
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
if (!delete(lastRet)) {
cursor = (cursor + 1) & (elements.length - 1);
fence = head;
}
lastRet = -1;
}
}
public boolean contains(Object o) {
if (o == null)
return false;
int mask = elements.length - 1;
int i = head;
E x;
while ( (x = elements[i]) != null) {
if (o.equals(x))
return true;
i = (i + 1) & mask;
}
return false;
}
public boolean remove(Object o) {
return removeFirstOccurrence(o);
}
public void clear() {
int h = head;
int t = tail;
if (h != t) { // clear all cells
head = tail = 0;
int i = h;
int mask = elements.length - 1;
do {
elements[i] = null;
i = (i + 1) & mask;
} while (i != t);
}
}
public Object[] toArray() {
return copyElements(new Object[size()]);
}
public <T> T[] toArray(T[] a) {
int size = size();
if (a.length < size)
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
copyElements(a);
if (a.length > size)
a[size] = null;
return a;
}
public ArrayDequeList<E> clone() {
try {
ArrayDequeList<E> result = (ArrayDequeList<E>) super.clone();
result.elements = Arrays.copyOf(elements, elements.length);
return result;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
private static final long serialVersionUID = 2340785798034038923L;
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
// Write out size
s.writeInt(size());
// Write out elements in order.
int mask = elements.length - 1;
for (int i = head; i != tail; i = (i + 1) & mask)
s.writeObject(elements[i]);
}
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
// Read in size and allocate array
int size = s.readInt();
allocateElements(size);
head = 0;
tail = size;
// Read in all elements in the proper order.
for (int i = 0; i < size; i++)
elements[i] = (E)s.readObject();
}
}

Related

Node class is an internal class in my code?

I'm asked this question and I'm not really sure what it means,
In our LinkedList class, the Node class is an internal class. Briefly
describe two things that would have to be coded differently if the
Node class was a separate class from the LinkedList class.
Here's the code for my LinkedList class:
public class LinkedList<T> implements LinkedListInterface<T> {
private Node head;
private Node tail;
private int count;
public LinkedList() {
head = null;
tail = null;
count = 0;
}
class Node {
T data;
Node next;
Node(T data) {
this.data = data;
next = null;
}
}
public Node getHead() {
return head;
}
public int add(T item) {
Node newNode = new Node(item);
if (isEmpty()) {
head = newNode;
} else {
tail.next = newNode;
}
tail = newNode;
count++;
return count;
}
public void add(T item, int pos) throws ListException {
if (pos < 1 || pos > count + 1) {
throw new ListException("Invalid position to insert at");
}
Node newNode = new Node(item);
if (count == 0) {
add(item);
} else if (pos == count + 1) {
add(item);
} else if (pos == 1) {
newNode.next = head;
head = newNode;
count++;
} else {
Node prev = jump(pos - 2);
newNode.next = prev.next;
prev.next = newNode;
count++;
}
}
private Node jump(int numJumps) {
Node nd = head;
for (int i = 0; i < numJumps; i++) {
nd = nd.next;
}
return nd;
}
public LinkedList<T> combine(LinkedList<T> obj2) {
Node list1 = this.getHead();
Node list2 = obj2.getHead();
if (list2 == null) {
return this;
}
if(list1==null) {
return obj2;
}
Node temp=list1;
while(temp.next!=null) {
temp = temp.next;
}
temp.next=list2;
return this;
}
public int contains(T item) {
Node nd = this.head;
for (int pos = 1; pos <= count; pos++) {
if (nd.data.equals(item)) {
return pos;
}
nd = nd.next;
}
return 0;
}
public LinkedList<T> copy() {
LinkedList<T> l = new LinkedList<T>();
try {
for (int pos = 1; pos <= count; pos++)
l.add(retrieve(pos));
}
catch(ListException e) {
System.out.println("Should not occur (Copy)");
}
return l;
}
public boolean equals(Object list) {
if (list == null) {
return false;
}
LinkedList myLinkedList = (LinkedList)list;
if(myLinkedList.getClass() != this.getClass()) {
return false;
}
if(myLinkedList.length() != this.length()) {
return false;
}
try{
for (int pos = 1; pos <= count; pos++) {
if(!myLinkedList.retrieve(pos).equals(this.retrieve(pos))) {
return false;
}
}
}
catch (ListException e) {
System.out.println("Should not occur");
}
return true;
}
public boolean isEmpty() {
return length() == 0;
}
public int length() {
return count;
}
#SuppressWarnings("unchecked")
public T remove(int pos) throws ListException {
if (pos < 1 || pos > count) {
throw new ListException("Invalid position to remove from");
}
Node removedItem = null;
if (count == 1) {
removedItem = head;
head = null;
tail = null;
} else if (pos == 1) {
removedItem = head;
head = head.next;
} else if (pos == count) {
removedItem = tail;
Node prev = jump(pos - 2);
prev.next = null;
tail = prev;
} else {
Node prev = jump(pos - 2);
removedItem = prev.next;
prev.next = prev.next.next;
}
count--;
return removedItem.data;
}
public int remove(T item) {
int numRemoved = 0;
int pos = -1;
try {
while ((pos = contains(item)) > 0) {
remove(pos);
numRemoved++;
}
} catch (ListException e){
System.out.print(e);
}
return numRemoved;
}
int find_length(Node list){
int count = 0;
while (list!=null) {
count++;
list=list.next;
}
return count;
}
public void replace(T item, int pos) throws ListException {
if (pos < 1 || pos > count + 1) {
throw new ListException("Invalid position to replace at");
}
Node list = this.getHead();
int length = find_length(list);
if(pos<1||pos>length){
return;
}
while(list!=null){
pos--;
if(pos==0){
list.data=item;
return;
}
list=list.next;
}
}
public T retrieve(int pos) throws ListException {
T item = null;
if (pos < 1 || pos > count) {
throw new ListException("Invalid position to retrieve from");
}
if (pos == 1) {
return head.data;
}
Node prev = jump(pos - 2);
item = prev.next.data;
return item;
}
public LinkedList<T> reverse() {
LinkedList<T> l = new LinkedList<T>();
try {
for (int pos = count; pos > 0; pos--)
l.add(retrieve(pos));
}
catch (ListException e) {
System.out.println("Should not occur (Reverse)");
}
return l;
}
public String toString() {
String temp = "";
Node nd = head;
while (nd != null) {
temp += nd.data + "-";
nd = nd.next;
}
return temp;
}
}
What I'm trying to get is the since the Node class is located in the same class as my LinkedList class, it is referred to as an internal class. If it were to be separate, would I have to implement a Node class similarly to the LinkedListInterface<T> class? What else would have to be coded differently?

Deque AddFront causing junit errors

I have to write code for Dequeue using a circular array I am getting null pointer exceptions that point to my addFront method, I feel like the logic is correct but I just can't seem to get what's wrong. A full queue is indicated by when rear is 2 positions counter clockwise from front. And an empty queue is indicated by when rear is 1 position counter clockwise from front.
Here is my code:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class Dequeue<E> {
private E elements[];
private int front;
private int rear;
private static final int INITIAL_CAPACITY = 5;
/** Creates a queue with an initial capacity of 5 */
#SuppressWarnings("unchecked")
public Dequeue(int INITIAL_CAPACITY) {
elements = (E[]) new Object[INITIAL_CAPACITY];
front = 0;
rear = -1;
}
public Dequeue() {
front = 1;
rear = 0;
}
public int size() {
return elements.length;
}
public boolean empty() {
return (rear + 1 == front);
}
public boolean isFull() {
return (front == rear + 2);
}
#SuppressWarnings("unchecked")
private void resize() {
E[] temp = (E[]) new Object[(elements.length * 2)+1]; // new array
int i = 0; // use this to control new array positions
int j = front; // use this to control old array positions
boolean rearReached = false;
while (!rearReached) {
rearReached = j % elements.length == rear; // is true if we've reached the rear
temp[i] = elements[j % elements.length];
i++;
j++;
}
front = 0;
rear = elements.length - 1;
elements = temp;
}
public boolean addFront(E item) {
// check whether Deque if full or not
if (isFull()) {
resize();
}
if (elements.length == 0) {
elements[front] = item;
} else if (front == 0){
front = elements.length - 1 ;
elements[front] = item;
} else {
front--;
elements[front] = item;
}
return true;
}
public boolean addRear(E item) {
if (isFull()) {
resize();
rear++;
elements[rear] = item;
} else if (empty()) {
rear++;
elements[rear] = item;
}
return elements[rear] == item;
}
public E peekFront() {
// check whether Deque is empty or not
if (empty()) {
throw new NoSuchElementException("Empty Deque");
}
E result = elements[front];
return result;
}
public E peekRear() {
// check whether Deque is empty or not
if (empty()) {
throw new NoSuchElementException("Empty Deque");
}
E result = elements[rear];
return result;
}
public E removeFront() {
// check whether Deque is empty or not
if (empty()) {
throw new NoSuchElementException("Empty Deque");
}
// Deque has only one element
if (front == rear) {
front = -1;
rear = -1;
} else
// back to initial position
if (front == size() - 1)
front = 0;
else // increment front by '1' to remove current
// front value from Deque
front++;
return elements[front];
}
public E removeRear() {
if (empty()) {
throw new NoSuchElementException("Empty Deque");
}
// Deque has only one element
if (front == rear) {
front = -1;
rear = -1;
} else if (rear == 0)
rear = size() - 1;
else
rear = rear - 1;
return elements[rear];
}
public Iterator<E> iterator() {
Iterator<E> it = new Iterator<E>() {
private int currentIndex = front;
#Override
public boolean hasNext() {
return currentIndex < size() && elements[currentIndex] != elements[rear];
}
#Override
public E next() {
return elements[currentIndex++];
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
};
return it;
}
}

Recursively find nth to last element in linked list

I'm practicing basic data structure stuff and I'm having some difficulties with recursion. I understand how to do this through iteration but all of my attempts to return the nth node from the last of a linked list via recursion result in null. This is my code so far:
public static int i = 0;
public static Link.Node findnthToLastRecursion(Link.Node node, int pos) {
if(node == null) return null;
else{
findnthToLastRecursion(node.next(), pos);
if(++i == pos) return node;
return null;
}
Can anyone help me understand where I'm going wrong here?
This is my iterative solution which works fine, but I'd really like to know how to translate this into recursion:
public static Link.Node findnthToLast(Link.Node head, int n) {
if (n < 1 || head == null) {
return null;
}
Link.Node pntr1 = head, pntr2 = head;
for (int i = 0; i < n - 1; i++) {
if (pntr2 == null) {
return null;
} else {
pntr2 = pntr2.next();
}
}
while (pntr2.next() != null) {
pntr1 = pntr1.next();
pntr2 = pntr2.next();
}
return pntr1;
}
You need to go to the end and then count your way back, make sure to pass back the node each time its passed back. I like one return point
public static int i = 0;
public static Link.Node findnthToLastRecursion(Link.Node node, int pos) {
Link.Node result = node;
if(node != null) {
result = findnthToLastRecursion(node.next, pos);
if(i++ == pos){
result = node;
}
}
return result;
}
Working example outputs 7 as 2 away from the 9th and last node:
public class NodeTest {
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
/**
* #param args
*/
public static void main(String[] args) {
Node first = null;
Node prev = null;
for (int i = 0; i < 10; i++) {
Node current = new Node(prev, Integer.toString(i),null);
if(i==0){
first = current;
}
if(prev != null){
prev.next = current;
}
prev = current;
}
System.out.println( findnthToLastRecursion(first,2).item);
}
public static int i = 0;
public static Node findnthToLastRecursion(Node node, int pos) {
Node result = node;
if (node != null) {
result = findnthToLastRecursion(node.next, pos);
if (i++ == pos) {
result = node;
}
}
return result;
}
}
No need for static variables.
public class List {
private Node head = null;
// [...] Other methods
public Node findNthLastRecursive(int nth) {
if (nth <= 0) return null;
return this.findNthLastRecursive(this.head, nth, new int[] {0});
}
private Node findNthLastRecursive(Node p, int nth, int[] pos) {
if (p == null) {
return null;
}
Node n = findNthLastRecursive(p.next, nth, pos);
pos[0]++;
if (pos[0] == nth) {
n = p;
}
return n;
}
}
You can do this a couple of ways:
recurse through the list once to find the list length, then write a recursive method to return the kth element (a much easier problem).
use an auxiliary structure to hold the result plus the remaining length; this essentially replaces the two recursions of the first option with a single recursion:
static class State {
Link.Node result;
int trailingLength;
}
public static Link.Node findnthToLastRecursion(Link.Node node, int pos) {
if(node == null) return null;
State state = new State();
findnthToLastRecursion(node, pos, state);
return state.result;
}
private static void findnthToLastRecursion(Link.Node node, int pos, State state) {
if (node == null) {
state.trailingLength = 0;
} else {
findnthToLastRecursion(node.next(), state);
if (pos == state.trailingLength) {
state.result = node;
}
++state.trailingLength;
}
}
I misunderstood the question. Here is an answer based on your iterative solution:
public static Link.Node findnthToLast(Link.Node head, int n) {
return findnthToLastHelper(head, head, n);
}
private static Link.Node findnthToLastHelper(Link.Node head, Link.Node end, int n) {
if ( end == null ) {
return ( n > 0 ? null : head);
} elseif ( n > 0 ) {
return findnthToLastHelper(head, end.next(), n-1);
} else {
return findnthToLastHelper(head.next(), end.next(), 0);
}
}
actually you don't need to have public static int i = 0; . for utill method the pos is :
pos = linked list length - pos from last + 1
public static Node findnthToLastRecursion(Node node, int pos) {
if(node ==null){ //if null then return null
return null;
}
int length = length(node);//find the length of the liked list
if(length < pos){
return null;
}
else{
return utill(node, length - pos + 1);
}
}
private static int length(Node n){//method which finds the length of the linked list
if(n==null){
return 0;
}
int count = 0;
while(n!=null){
count++;
n=n.next;
}
return count;
}
private static Node utill(Node node, int pos) {
if(node == null) {
return null;
}
if(pos ==1){
return node;
}
else{
return utill(node.next, pos-1);
}
}
Here node.next is the next node. I am directly accessing the next node rather than calling the next() method. Hope it helps.
This cheats (slightly) but it looks good.
public class Test {
List<String> list = new ArrayList<> (Arrays.asList("Zero","One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten"));
public static String findNthToLastUsingRecursionCheatingALittle(List<String> list, int n) {
int s = list.size();
return s > n
// Go deeper!
? findNthToLastUsingRecursionCheatingALittle(list.subList(1, list.size()), n)
// Found it.
: s == n ? list.get(0)
// Too far.
: null;
}
public void test() {
System.out.println(findNthToLastUsingRecursionCheating(list,3));
}
public static void main(String args[]) {
new Test().test();
}
}
It prints:
Eight
which I suppose is correct.
I have use List instead of some LinkedList variant because I do not want to reinvent anything.
int nthNode(struct Node* head, int n)
{
if (head == NULL)
return 0;
else {
int i;
i = nthNode(head->left, n) + 1;
printf("=%d,%d,%d\n", head->data,i,n);
if (i == n)
printf("%d\n", head->data);
}
}
public class NthElementFromLast {
public static void main(String[] args) {
List<String> list = new LinkedList<>();
Stream.of("A","B","C","D","E").forEach(s -> list.add(s));
System.out.println(list);
System.out.println(getNthElementFromLast(list,2));
}
private static String getNthElementFromLast(List list, int positionFromLast) {
String current = (String) list.get(0);
int index = positionFromLast;
ListIterator<String> listIterator = list.listIterator();
while(positionFromLast>0 && listIterator.hasNext()){
positionFromLast--;
current = listIterator.next();
}
if(positionFromLast != 0) {
return null;
}
String nthFromLast = null;
ListIterator<String> stringListIterator = list.listIterator();
while(listIterator.hasNext()) {
current = listIterator.next();
nthFromLast = stringListIterator.next();
}
return nthFromLast;
}
}
This will find Nth element from last.
My approach is simple and straight,you can change the array size depending upon your requirement:
int pos_from_tail(node *k,int n)
{ static int count=0,a[100];
if(!k) return -1;
else
pos_from_tail(k->next,n);
a[count++]=k->data;
return a[n];
}
You'll have make slight changes in the code:
public static int i = 0;
public static Link.Node findnthToLastRecursion(Link.Node node, int pos) {
if(node == null) return null;
else{
**Link.Node temp = findnthToLastRecursion(node.next(), pos);
if(temp!=null)
return temp;**
if(++i == pos) return node;
return null;
}
}

Binary Heap Implemented via a Binary Tree Structure

For an assignment, we were instructed to create a priority queue implemented via a binary heap, without using any built-in classes, and I have done so successfully by using an array to store the queued objects. However, I'm interested in learning how to implement another queue by using an actual tree structure, but in doing so I've run across a bit of a problem.
How would I keep track of the nodes on which I would perform insertion and deletion? I have tried using a linked list, which appends each node as it is inserted - new children are added starting from the first list node, and deleted from the opposite end. However, this falls apart when elements are rearranged in the tree, as children are added at the wrong position.
Edit: Perhaps I should clarify - I'm not sure how I would be able to find the last occupied and first unoccupied leaves. For example, I would always be able to tell the last inserted leaf, but if I were to delete it, how would I know which leaf to delete when I next remove the item? The same goes for inserting - how would I know which leaf to jump to next after the current leaf has both children accounted for?
A tree implementation of a binary heap uses a complete tree [or almost full tree: every level is full, except the deepest one].
You always 'know' which is the last occupied leaf - where you delete from [and modifying it is O(logn) after it changed so it is not a problem], and you always 'know' which is the first non-occupied leaf, in which you add elements to [and again, modifying it is also O(logn) after it changed].
The algorithm idea is simple:
insert: insert element to the first non-occupied leaf, and use heapify [sift up] to get this element to its correct place in the heap.
delete_min: replace the first element with the last occupied leaf, and remove the last occupied leaf. then, heapify [sift down] the heap.
EDIT: note that delete() can be done to any element, and not only the head, however - finding the element you want to replace with the last leaf will be O(n), which will make this op expensive. for this reason, the delete() method [besides the head], is usually not a part of the heap data structure.
I really wanted to do this for almost a decade.Finally sat down today and wrote it.Anyone who wants it can use it.I got inspired by Quora founder to relearn Heap.Apparently he was asked how would you find K near points in a set of n points in his Google phone screen.Apparently his answer was to use a Max Heap and to store K values and remove the maximum element after the size of the heap exceeds K.The approach is pretty simple and the worst case is nlog K which is better than n^2 in most sorting cases.Here is the code.
import java.util.ArrayList;
import java.util.List;
/**
* #author Harish R
*/
public class HeapPractise<T extends Comparable<T>> {
private List<T> heapList;
public List<T> getHeapList() {
return heapList;
}
public void setHeapList(List<T> heapList) {
this.heapList = heapList;
}
private int heapSize;
public HeapPractise() {
this.heapList = new ArrayList<>();
this.heapSize = heapList.size();
}
public void insert(T item) {
if (heapList.size() == 0) {
heapList.add(item);
} else {
siftUp(item);
}
}
public void siftUp(T item) {
heapList.add(item);
heapSize = heapList.size();
int currentIndex = heapSize - 1;
while (currentIndex > 0) {
int parentIndex = (int) Math.floor((currentIndex - 1) / 2);
T parentItem = heapList.get(parentIndex);
if (parentItem != null) {
if (item.compareTo(parentItem) > 0) {
heapList.set(parentIndex, item);
heapList.set(currentIndex, parentItem);
currentIndex = parentIndex;
continue;
}
}
break;
}
}
public T delete() {
if (heapList.size() == 0) {
return null;
}
if (heapList.size() == 1) {
T item = heapList.get(0);
heapList.remove(0);
return item;
}
return siftDown();
}
public T siftDown() {
T item = heapList.get(0);
T lastItem = heapList.get(heapList.size() - 1);
heapList.remove(heapList.size() - 1);
heapList.set(0, lastItem);
heapSize = heapList.size();
int currentIndex = 0;
while (currentIndex < heapSize) {
int leftIndex = (2 * currentIndex) + 1;
int rightIndex = (2 * currentIndex) + 2;
T leftItem = null;
T rightItem = null;
int currentLargestItemIndex = -1;
if (leftIndex <= heapSize - 1) {
leftItem = heapList.get(leftIndex);
}
if (rightIndex <= heapSize - 1) {
rightItem = heapList.get(rightIndex);
}
T currentLargestItem = null;
if (leftItem != null && rightItem != null) {
if (leftItem.compareTo(rightItem) >= 0) {
currentLargestItem = leftItem;
currentLargestItemIndex = leftIndex;
} else {
currentLargestItem = rightItem;
currentLargestItemIndex = rightIndex;
}
} else if (leftItem != null && rightItem == null) {
currentLargestItem = leftItem;
currentLargestItemIndex = leftIndex;
}
if (currentLargestItem != null) {
if (lastItem.compareTo(currentLargestItem) >= 0) {
break;
} else {
heapList.set(currentLargestItemIndex, lastItem);
heapList.set(currentIndex, currentLargestItem);
currentIndex = currentLargestItemIndex;
continue;
}
}
}
return item;
}
public static void main(String[] args) {
HeapPractise<Integer> heap = new HeapPractise<>();
for (int i = 0; i < 32; i++) {
heap.insert(i);
}
System.out.println(heap.getHeapList());
List<Node<Integer>> nodeArray = new ArrayList<>(heap.getHeapList()
.size());
for (int i = 0; i < heap.getHeapList().size(); i++) {
Integer heapElement = heap.getHeapList().get(i);
Node<Integer> node = new Node<Integer>(heapElement);
nodeArray.add(node);
}
for (int i = 0; i < nodeArray.size(); i++) {
int leftNodeIndex = (2 * i) + 1;
int rightNodeIndex = (2 * i) + 2;
Node<Integer> node = nodeArray.get(i);
if (leftNodeIndex <= heap.getHeapList().size() - 1) {
Node<Integer> leftNode = nodeArray.get(leftNodeIndex);
node.left = leftNode;
}
if (rightNodeIndex <= heap.getHeapList().size() - 1) {
Node<Integer> rightNode = nodeArray.get(rightNodeIndex);
node.right = rightNode;
}
}
BTreePrinter.printNode(nodeArray.get(0));
}
}
public class Node<T extends Comparable<?>> {
Node<T> left, right;
T data;
public Node(T data) {
this.data = data;
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class BTreePrinter {
public static <T extends Comparable<?>> void printNode(Node<T> root) {
int maxLevel = BTreePrinter.maxLevel(root);
printNodeInternal(Collections.singletonList(root), 1, maxLevel);
}
private static <T extends Comparable<?>> void printNodeInternal(
List<Node<T>> nodes, int level, int maxLevel) {
if (nodes.isEmpty() || BTreePrinter.isAllElementsNull(nodes))
return;
int floor = maxLevel - level;
int endgeLines = (int) Math.pow(2, (Math.max(floor - 1, 0)));
int firstSpaces = (int) Math.pow(2, (floor)) - 1;
int betweenSpaces = (int) Math.pow(2, (floor + 1)) - 1;
BTreePrinter.printWhitespaces(firstSpaces);
List<Node<T>> newNodes = new ArrayList<Node<T>>();
for (Node<T> node : nodes) {
if (node != null) {
String nodeData = String.valueOf(node.data);
if (nodeData != null) {
if (nodeData.length() == 1) {
nodeData = "0" + nodeData;
}
}
System.out.print(nodeData);
newNodes.add(node.left);
newNodes.add(node.right);
} else {
newNodes.add(null);
newNodes.add(null);
System.out.print(" ");
}
BTreePrinter.printWhitespaces(betweenSpaces);
}
System.out.println("");
for (int i = 1; i <= endgeLines; i++) {
for (int j = 0; j < nodes.size(); j++) {
BTreePrinter.printWhitespaces(firstSpaces - i);
if (nodes.get(j) == null) {
BTreePrinter.printWhitespaces(endgeLines + endgeLines + i
+ 1);
continue;
}
if (nodes.get(j).left != null)
System.out.print("//");
else
BTreePrinter.printWhitespaces(1);
BTreePrinter.printWhitespaces(i + i - 1);
if (nodes.get(j).right != null)
System.out.print("\\\\");
else
BTreePrinter.printWhitespaces(1);
BTreePrinter.printWhitespaces(endgeLines + endgeLines - i);
}
System.out.println("");
}
printNodeInternal(newNodes, level + 1, maxLevel);
}
private static void printWhitespaces(int count) {
for (int i = 0; i < 2 * count; i++)
System.out.print(" ");
}
private static <T extends Comparable<?>> int maxLevel(Node<T> node) {
if (node == null)
return 0;
return Math.max(BTreePrinter.maxLevel(node.left),
BTreePrinter.maxLevel(node.right)) + 1;
}
private static <T> boolean isAllElementsNull(List<T> list) {
for (Object object : list) {
if (object != null)
return false;
}
return true;
}
}
Please note that BTreePrinter is a code I took somewhere in Stackoverflow long back and I modified to use with 2 digit numbers.It will be broken if we move to 3 digit numbers and it is only for simple understanding of how the Heap structure looks.A fix for 3 digit numbers is to keep everything as multiple of 3.
Also due credits to Sesh Venugopal for wonderful tutorial on Youtube on Heap data structure
public class PriorityQ<K extends Comparable<K>> {
private class TreeNode<T extends Comparable<T>> {
T val;
TreeNode<T> left, right, parent;
public String toString() {
return this.val.toString();
}
TreeNode(T v) {
this.val = v;
left = null;
right = null;
}
public TreeNode<T> insert(T val, int position) {
TreeNode<T> parent = findNode(position/2);
TreeNode<T> node = new TreeNode<T>(val);
if(position % 2 == 0) {
parent.left = node;
} else {
parent.right = node;
}
node.parent = parent;
heapify(node);
return node;
}
private void heapify(TreeNode<T> node) {
while(node.parent != null && (node.parent.val.compareTo(node.val) < 0)) {
T temp = node.val;
node.val = node.parent.val;
node.parent.val = temp;
node = node.parent;
}
}
private TreeNode<T> findNode(int pos) {
TreeNode<T> node = this;
int reversed = 1;
while(pos > 0) {
reversed <<= 1;
reversed |= (pos&1);
pos >>= 1;
}
reversed >>= 1;
while(reversed > 1) {
if((reversed & 1) == 0) {
node = node.left;
} else {
node = node.right;
}
reversed >>= 1;
}
return node;
}
public TreeNode<T> remove(int pos) {
if(pos <= 1) {
return null;
}
TreeNode<T> last = findNode(pos);
if(last.parent.right == last) {
last.parent.right = null;
} else {
last.parent.left = null;
}
this.val = last.val;
bubbleDown();
return null;
}
public void bubbleDown() {
TreeNode<T> node = this;
do {
TreeNode<T> left = node.left;
TreeNode<T> right = node.right;
if(left != null && right != null) {
T max = left.val.compareTo(right.val) > 0 ? left.val : right.val;
if(max.compareTo(node.val) > 0) {
if(left.val.equals(max)) {
left.val = node.val;
node.val = max;
node = left;
} else {
right.val = node.val;
node.val = max;
node = right;
}
} else {
break;
}
} else if(left != null) {
T max = left.val;
if(left.val.compareTo(node.val) > 0) {
left.val = node.val;
node.val = max;
node = left;
} else {
break;
}
} else {
break;
}
} while(true);
}
}
private TreeNode<K> root;
private int position;
PriorityQ(){
this.position = 1;
}
public void insert(K val) {
if(val == null) {
return;
}
if(root == null) {
this.position = 1;
root = new TreeNode<K>(val);
this.position++;
return ;
}
root.insert(val, position);
position++;
}
public K remove() {
if(root == null) {
return null;
}
K val = root.val;
root.remove(this.position-1);
this.position--;
if(position == 1) {
root = null;
}
return val;
}
public static void main(String[] args) {
PriorityQ<Integer> q = new PriorityQ<>();
System.out.println(q.remove());
q.insert(1);
q.insert(11);
q.insert(111);
q.insert(1111);
q.remove();
q.remove();
q.remove();
q.remove();
q.insert(2);
q.insert(4);
}
}

2-D (concurrent) HashMap: 2-property key type? hashmap of hashmaps? [update]

So I need a 2-dimensional ConcurrentHashMap.
It has to be as blazing fast as possible, as I'm going to be adding to and updating its values extremely frequently. It's in a multithreaded application, hence the choice to use ConcurrentHashMap instead of just HashMap.
Both the "x" and "y" indices are integers with a known range (0 through 40,000,000).
What I need to know is: What's the most efficient way to implement this so it'll be as speedy as possible? The most obvious route is to do a literal 2-D hashmap:
ConcurrentHashMap<Integer, ConcurrentHashMap<Integer, ValueObj>> foo;
Or I could make a private class "IntPair" with two properties x and y, and use that as a key... though if I do that, what's the most efficient way to do equals() and hashcode()? and will I wind up allocating too many new IntPairs? Could I keep a set of IntPairs for each x/y I've assigned, and then use a purely reflexive equals() such that I'm just checking for the exact same object instance?
Update:
Now that I've taken a closer look at Integer.valueOf(int), the specific caching model it uses wouldn't make sense here, since I'm dealing with a very sparse matrix with unpredictable entries. I really need to be caching all those IntPairs which are used, not a prespecified subset.
Intuitively, it seems to me that looking up an IntPair in a big map to see if I've already created it would, in fact, be more-or-less the same as just looking it up in the big "2-D" ConcurrentHashMap anyway, wouldn't it? So it seems the solution here is really to just use new IntPair(x,y) each time I look up a key. Yes?
It depends on how sparse your (x,y) points are, in the 40,000,000 x 40,000,000 matrix. My guess is that the matrix is going to be quite sparse anyway, so creating a lot of ConcurrentHashMaps is going to be expensive.
Your (immutable) IntPair suggestion seems more attractive in comparison. As you've suggested, you can even cache some of these pairs to improve performance (see Integer.valueOf(int) to see how this can be implemented using a static nested class and a static factory method). Since the hashcode will always be required, you can pre-compute it in the constructor and save it as a final field. To compute equals, you could use the identity equality for objects in the cache, otherwise you'll need to compare x and y individually.
EDIT: Here's the source code (OpenJDK) for Integer.valueOf(int).
ConcurrentHashMap is quite large, so you probably don't want a collection of them.
Short lived objects are actually very fast to allocate. Are you going to have to create the Integers anyway?
You could intern the coordinate objects, but the cost for just a lookup would probably be comparable to creating them anyway. The real win with Integer is that the same instances are shared when you keep around lots of them for some time.
If performance is really a huge issue, you could write (or use) a map-type object that maps longs to references. I wouldn't be surprised to see custom maps out there which also have functionality associated with coordinate systems (like finding nearest or within a range).
In response to Zach, Yes, the matrix will be very sparse.
I looked at the page you linked, and without a doubt the functionality of Integer.valueOf(int) would be ideal. If I developed a similar static method within my IntPair class, can I assume that I could define equals() to only check for strict reflexive equality?
That said, I don't see in that page where it explains how to implement that functionality using a static nested class and static factory method.... am I just missing it somehow? How do I do that?
Thanks!
I've made a Int2DMap implementation based on the standard Java HashMap. I find it is faster than using an IntPair as key. However it will need to be synchronized.
import java.io.*;
import java.util.*;
public class Int2DMap implements Map, Serializable {
private static final int DEFAULT_INITIAL_CAPACITY = 16;
private static final int MAXIMUM_CAPACITY = 1 << 30;
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
protected Entry[] table;
protected int size;
protected int threshold;
protected float loadFactor;
protected transient volatile int modCount;
public Int2DMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
// Find a power of 2 >= initialCapacity
int capacity = 1;
while (capacity < initialCapacity) {
capacity <<= 1;
}
this.loadFactor = loadFactor;
this.threshold = (int) (capacity * loadFactor);
this.table = new Entry[capacity];
}
public Int2DMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
public Int2DMap() {
this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
}
public boolean containsKey(Object key) {
int[] xy = (int[]) key;
return containsKey(xy[0], xy[1]);
}
public Object get(Object key) {
int[] xy = (int[]) key;
return get(xy[0], xy[1]);
}
public Object put(Object key, Object value) {
int[] xy = (int[]) key;
return put(xy[0], xy[1], value);
}
public Object remove(Object key) {
int[] xy = (int[]) key;
return remove(xy[0], xy[1]);
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
protected static final int indexFor(int x, int y, int length) {
return (x * 31 + y) & (length - 1);
}
public Object get(int x, int y) {
for (Entry e = table[indexFor(x, y, table.length)]; e != null; e = e.next) {
if (e.x == x && e.y == y) {
return e.value;
}
}
return null;
}
public boolean containsKey(int x, int y) {
return getEntry(x, y) != null;
}
protected Entry getEntry(int x, int y) {
for (Entry e = table[indexFor(x, y, table.length)]; e != null; e = e.next) {
if (e.x == x && e.y == y) {
return e;
}
}
return null;
}
public Object put(int x, int y, Object value) {
int i = indexFor(x, y, table.length);
for (Entry e = table[i]; e != null; e = e.next) {
if (e.x == x && e.y == y) {
Object oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(x, y, value, i);
return null;
}
protected void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
transfer(newTable);
table = newTable;
threshold = (int) (newCapacity * loadFactor);
}
protected void transfer(Entry[] newTable) {
Entry[] src = table;
int newCapacity = newTable.length;
for (int j = 0; j < src.length; j++) {
Entry e = src[j];
if (e != null) {
src[j] = null;
do {
Entry next = e.next;
int i = indexFor(e.x, e.y, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
}
}
}
public void putAll(Map m) {
int numKeysToBeAdded = m.size();
if (numKeysToBeAdded == 0) {
return;
}
if (numKeysToBeAdded > threshold) {
int targetCapacity = (int) (numKeysToBeAdded / loadFactor + 1);
if (targetCapacity > MAXIMUM_CAPACITY)
targetCapacity = MAXIMUM_CAPACITY;
int newCapacity = table.length;
while (newCapacity < targetCapacity)
newCapacity <<= 1;
if (newCapacity > table.length)
resize(newCapacity);
}
for (Iterator i = m.entrySet().iterator(); i.hasNext();) {
Map.Entry e = (Map.Entry) i.next();
put(e.getKey(), e.getValue());
}
}
public Object remove(int x, int y) {
Entry e = removeEntryForKey(x, y);
return (e == null ? null : e.value);
}
protected Entry removeEntryForKey(int x, int y) {
int i = indexFor(x, y, table.length);
Entry prev = table[i];
Entry e = prev;
while (e != null) {
Entry next = e.next;
Object k;
if (e.x == x && e.y == y) {
modCount++;
size--;
if (prev == e)
table[i] = next;
else
prev.next = next;
e.recordRemoval(this);
return e;
}
prev = e;
e = next;
}
return e;
}
protected Entry removeMapping(Object o) {
if (!(o instanceof Entry))
return null;
Entry entry = (Entry) o;
int x = entry.x;
int y = entry.y;
int i = indexFor(x, y, table.length);
Entry prev = table[i];
Entry e = prev;
while (e != null) {
Entry next = e.next;
if (e.x == x && e.y == y) {
modCount++;
size--;
if (prev == e)
table[i] = next;
else
prev.next = next;
e.recordRemoval(this);
return e;
}
prev = e;
e = next;
}
return e;
}
public void clear() {
modCount++;
Entry[] tab = table;
for (int i = 0; i < tab.length; i++)
tab[i] = null;
size = 0;
}
public boolean containsValue(Object value) {
Entry[] tab = table;
for (int i = 0; i < tab.length; i++)
for (Entry e = tab[i]; e != null; e = e.next)
if (value.equals(e.value))
return true;
return false;
}
static class Entry implements Map.Entry {
final int x;
final int y;
Object value;
Entry next;
Entry(int x, int y, Object value, Entry next) {
this.x = x;
this.y = y;
this.value = value;
this.next = next;
}
public final Object getKey() {
return new int[] { x, y };
}
public final Object getValue() {
return value;
}
public final Object setValue(Object newValue) {
Object oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry) o;
int[] xy = (int[])e.getKey();
if (x == xy[0] && y == xy[1]) {
Object v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
}
public final int hashCode() {
return ((31 + x) * 31 + y);
}
public final String toString() {
return "[" + x + ", " + y + "]=" + value;
}
/**
* This method is invoked whenever the value in an entry is overwritten by
* an invocation of put(k,v) for a key k that's already in the HashMap.
*/
void recordAccess(Int2DMap m) {
}
/**
* This method is invoked whenever the entry is removed from the table.
*/
void recordRemoval(Int2DMap m) {
}
}
void addEntry(int x, int y, Object value, int bucketIndex) {
Entry e = table[bucketIndex];
table[bucketIndex] = new Entry(x, y, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}
private abstract class HashIterator implements Iterator {
Entry next; // next entry to return
int expectedModCount; // For fast-fail
int index; // current slot
Entry current; // current entry
HashIterator() {
expectedModCount = modCount;
if (size > 0) { // advance to first entry
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
}
public final boolean hasNext() {
return next != null;
}
final Entry nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Entry e = current = next;
if (e == null)
throw new NoSuchElementException();
if ((next = e.next) == null) {
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
return e;
}
public void remove() {
if (current == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
int x = current.x;
int y = current.y;
current = null;
Int2DMap.this.removeEntryForKey(x, y);
expectedModCount = modCount;
}
}
private final class ValueIterator extends HashIterator {
public Object next() {
return nextEntry().value;
}
}
private final class KeyIterator extends HashIterator {
public Object next() {
return nextEntry().getKey();
}
}
private final class EntryIterator extends HashIterator {
public Map.Entry next() {
return nextEntry();
}
}
// Subclass overrides these to alter behavior of views' iterator() method
Iterator newKeyIterator() {
return new KeyIterator();
}
Iterator newValueIterator() {
return new ValueIterator();
}
Iterator newEntryIterator() {
return new EntryIterator();
}
public Set keySet() {
return new KeySet();
}
private final class KeySet extends AbstractSet {
public Iterator iterator() {
return newKeyIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsKey(o);
}
public boolean remove(Object o) {
int[] xy = (int[]) o;
return Int2DMap.this.removeEntryForKey(xy[0], xy[1]) != null;
}
public void clear() {
Int2DMap.this.clear();
}
}
public Collection values() {
return new Values();
}
private final class Values extends AbstractCollection {
public Iterator iterator() {
return newValueIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsValue(o);
}
public void clear() {
Int2DMap.this.clear();
}
}
public Set entrySet() {
return new EntrySet();
}
private final class EntrySet extends AbstractSet {
public Iterator iterator() {
return newEntryIterator();
}
public boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Entry e = (Entry) o;
Entry candidate = getEntry(e.x, e.y);
return candidate != null && candidate.equals(e);
}
public boolean remove(Object o) {
return removeMapping(o) != null;
}
public int size() {
return size;
}
public void clear() {
Int2DMap.this.clear();
}
}
public static void main(String[] args) {
try {
Int2DMap map = new Int2DMap();
map.put(20, 6000, "Test");
System.out.println(map.size() == 1);
System.out.println(map.get(20, 6000) != null);
System.out.println("Test".equals(map.get(20, 6000)));
for (Iterator iter = map.values().iterator(); iter.hasNext();) {
System.out.println("Test".equals(iter.next()));
}
for (Iterator iter = map.keySet().iterator(); iter.hasNext();) {
int[] key = (int[])iter.next();
System.out.println(key[0] == 20 && key[1] == 6000);
}
for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
Map.Entry e = (Map.Entry)iter.next();
System.out.println(e.toString().equals("[20, 6000]=Test"));
}
map.remove(20, 6000);
System.out.println(map.size() == 0 && map.get(20, 6000) == null);
long start = System.nanoTime();
int max = 40000000;
for (int i = 0; i < 500000; i++) {
int x = (int)(Math.random() * max);
int y = (int)(Math.random() * max);
map.put(x, y, "");
int x2 = (int)(Math.random() * max);
int y2 = (int)(Math.random() * max);
Object o = map.get(x2, y2);
}
System.out.println(map.size());
System.out.println((System.nanoTime() - start) / 1000000);
Map map2 = new HashMap();
start = System.nanoTime();
for (int i = 0; i < 500000; i++) {
String key = "" + (int)(Math.random() * max) + "," + (int)(Math.random() * max);
map2.put(key, "");
String key2 = "" + (int)(Math.random() * max) + "," + (int)(Math.random() * max);
Object o = map2.get(key2);
}
System.out.println(map2.size());
System.out.println((System.nanoTime() - start) / 1000000);
} catch (Throwable t) {
t.printStackTrace();
}
}
}

Categories