This code reverses each consecutive n elements of a linked list, and for spare nodes, leaves them as they are.
For example, the linked list
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7
for an interval of 3 should result in
3 -> 2 -> 1-> 6 -> 5 -> 4 -> 7
Note that 7 is left as it is as its spare.
I'm looking for code review, optimization and best practices.
public class ReverseAtInterval<T> implements Iterable<T> {
private Node<T> first;
private Node<T> last;
private int size;
public ReverseAtInterval(List<T> c) {
for (T item : c) {
add(item);
}
}
public void add (T t) {
final Node<T> l = last;
final Node<T> node = new Node<T>(t, null);
last = node;
if (first == null) {
first = node;
} else {
l.next = node;
}
size++;
}
private static class Node<T> {
T item;
Node<T> next;
Node(T item, Node<T> next) {
this.item = item;
this.next = next;
}
}
private static class ReversedFirstLastNextData<T> {
Node<T> first; // first node in the reversed list.
Node<T> last; // last node in the reversed list.
Node<T> next; // next node - this node is not a part of revered list
public ReversedFirstLastNextData(Node<T> first, Node<T> last, Node<T> next) {
this.first = first;
this.last = last;
this.next = next;
}
}
private ReversedFirstLastNextData<T> reverse(Node<T> start, int n) {
Node<T> prev = null;
Node<T> ptr = start;
Node<T> ptr1 = null;
int ctr = 0;
while (ctr < n) {
ptr1 = ptr.next;
ptr.next = prev;
// advance forward.
prev = ptr;
ptr = ptr1;
ctr++;
}
return new ReversedFirstLastNextData<T>(prev, start, ptr);
}
public void reverseAtInterval(int n) {
int ctr = 0;
ReversedFirstLastNextData<T> prev = null;
ReversedFirstLastNextData<T> current = null;
Node<T> inputNode = first;
while (ctr < (size/n)) {
current = reverse(inputNode, n);
if (prev == null) {
first = current.first;
} else {
prev.last.next = current.first;
}
inputNode = current.next;
prev = current;
ctr++;
}
current.last.next = current.next;
}
@Override
public Iterator<T> iterator() {
return new LinkedListItr();
}
private class LinkedListItr implements Iterator<T> {
private Node<T> prev;
private Node<T> current;
private int currentSize = 0;
private int initialCapacity;
public LinkedListItr() {
this.current = first;
this.currentSize = 0;
initialCapacity = size;
}
@Override
public boolean hasNext() {
return currentSize < size;
}
@Override
public T next() {
if (initialCapacity != size) {
throw new ConcurrentModificationException();
}
if (!hasNext()) {
throw new NoSuchElementException();
}
currentSize++;
prev = current;
T item = current.item;
current = current.next;
return item;
}
@Override
public void remove() {
if (initialCapacity != size) {
throw new ConcurrentModificationException();
}
if (!hasNext()) {
throw new NoSuchElementException();
}
prev.next = current.next;
size--;
initialCapacity--;
}
}
public List<T> toArray() {
List<T> list = new ArrayList<T>();
Node<T> ptr = first;
while (ptr != null) {
list.add(ptr.item);
ptr = ptr.next;
}
return list;
}
}
public class ReverseAtIntervalTest {
@Test
public void testEven() {
ReverseAtInterval<Integer> rai = new ReverseAtInterval<Integer>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8));
rai.reverseAtInterval(4);
assertEquals(Arrays.asList(4, 3, 2, 1, 8, 7, 6, 5), rai.toArray());
}
@Test
public void testOdd() {
ReverseAtInterval<Integer> rai = new ReverseAtInterval<Integer>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8));
rai.reverseAtInterval(3);
assertEquals(Arrays.asList(3, 2, 1, 6, 5, 4, 7, 8), rai.toArray());
}
}
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
lead to3 -> 2 -> 1-> 6 -> 5 -> 4 -> 7 -> 8
(7 and 8 kept in the same order because we cannot form a triplet) or3 -> 2 -> 1-> 6 -> 5 -> 4 -> 8 -> 7
(7 and 8 in reverse order as if they were the beginning of a triplet) ? \$\endgroup\$ – SylvainD May 20 '14 at 10:25