1

I got a task where I have to reverse a List with one or more ListIterators. I am not allowed to use the Method collections.reverse() or other Methods like that. I am also not allowed to make a new field. I can't just use a new List as well. The input has to be changed!

This is what I got so far. But the input isn't changed:

public static <T> List<T> reverse(List <T> input) {
    ListIterator <T> listIterator2 = input.listIterator(input.size());
     ListIterator <T> listIterator =  input.listIterator(input.size());
     int u = input.size()-1;
     while(listIterator.hasNext()) {        
             listIterator.next();
            while (listIterator2.hasPrevious()) {
                listIterator.set(input.get(u));
                 listIterator2.previous(); 
                 u--;
            }
     }
     return input;
}
Naman
  • 27,789
  • 26
  • 218
  • 353
Anton Moog
  • 13
  • 2

4 Answers4

3

Here's a way to solve the problem recursively:

static <T> void reverse(List<T> list) {
    reverse0(list.listIterator(), list.listIterator());
}

static <T> void reverse0(ListIterator<T> in, ListIterator<T> out) {
    if (in.hasNext()) {
        T t = in.next();
        reverse0(in, out);
        out.next();
        out.set(t);
    }
}

This recurs all the way down to the end of the list using one iterator, and then on the way back up the call stack it runs forward through the list using the second iterator, setting elements along the way. This doesn't use a second list, although you could say it's cheating because the entire contents of the list are stored on the call stack....

Here's a non-recursive approach, using a similar technique to what others have shown. I think the loop and swapping logic are a bit simpler, though:

static <T> void reverse_nonrecur(List<T> list) {
    ListIterator<T> fwd = list.listIterator();
    ListIterator<T> rev = list.listIterator(list.size());
    while (rev.previousIndex() > fwd.nextIndex()) {
        T t = rev.previous();
        rev.set(fwd.next());
        fwd.set(t);
    }
}

I've avoided using Collections.swap since that seems to be a restriction of the problem (but you wouldn't want to use it to swap elements if the list were a LinkedList (but you should almost never be using LinkedList anyway)).

Stuart Marks
  • 127,867
  • 37
  • 205
  • 259
1

Doing this with iterators is a weird way, as the Collections.swap method (which is probably the easiest way to get what you need to achieve) specifically asks for indexes. So using those in the first place would be the way to go. Nonetheless, you can obviously also do this with iterators. This could look like the following:

public static <T> List<T> reverse(List<T> input)
{
    ListIterator<T> it = input.listIterator();
    ListIterator<T> itR = input.listIterator(input.size());

    while (it.nextIndex() - itR.previousIndex() < 0)
    {
        Collections.swap(input, it.nextIndex(), itR.previousIndex());
        it.next();
        itR.previous();
    }

    return input;
}

You begin by setting up your iterators. One starts at the beginning of the list, one at the end.

Then you loop as long as it.nextIndex() - itR.previousIndex() < 0. This is basically moving both iterators to the center of the List without them crossing so you don't swap back already swapped elements.

Finally you simply swap the elements at the corresponding indexes and move the iterators.

Update

As you specified that you can't directly use Collections.swap (for whatever reason) you can obviously also reinvent the wheel and just rewrite what the method does.

public static <T> List<T> reverse(List<T> input)
{
    ListIterator<T> it = input.listIterator();
    ListIterator<T> itR = input.listIterator(input.size());

    while (it.nextIndex() - itR.previousIndex() < 0)
    {
        T temp = input.get(it.nextIndex());
        input.set(it.nextIndex(), input.get(itR.previousIndex()));
        input.set(itR.previousIndex(), temp);

        it.next();
        itR.previous();
    }

    return input;
}

Does the exact same just without using the (honestly in all cases preferred) Collections.swap method.

Ben
  • 1,665
  • 1
  • 11
  • 22
  • I know that doing it with Iterators is a weird way. But the Task is designed to leaern how to use Iterators, so just swapping the List with Collections.swap isnt allowed. Wtih your help I have come a little bit further but my code still has some problems. – Anton Moog May 04 '18 at 12:17
  • @AntonMoog I've updated my answer. I don't exactly know how this teaches you anything more about Iterators but I guess a task is a task. – Ben May 04 '18 at 12:34
1

Using ListIterator<T> for this issue is pretty weird, however here is the solution which iterates the list twice. Here we go without using the Collections class:

public static <T> List<T> reverse(List <T> input) {
    ListIterator<T> iterator = input.listIterator(input.size());
    List<T> reversedList = new ArrayList<>(input.size());
    while (iterator.hasPrevious()) {
        T temp = iterator.previous();
        reversedList.add(temp);
    }
    return reversedList;
}

Edit: I made a mistake. The method ListIterator<E> listIterator(int index) provides a ListIterator starting on the index. Since you start in the end, you can iterate once and add all the elements to anew List.


Edit2: Without creating a new list, I have found you have to iterate the half of the List and get items from the end/beginning to the middle and swap them.

public static <T> List<T> reverse(List <T> input) {
    ListIterator<T> iterator = input.listIterator(input.size());
    ListIterator<T> reversedIterator = input.listIterator();
    for (int i=0; i<input.size()/2; i++) {
        T previous = iterator.previous();
        T next  = reversedIterator.next();
        iterator.set(next);
        reversedIterator.set(previous);
    }
    return input;
}
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
  • It was specified that they are not allowed to create a new list. So it's basically forcing one into `swap` from my standpoint. – Ben May 04 '18 at 12:36
0

Something like this?

 private static <T> List<T> reverse(List<T> list) {
        ListIterator<T> fIterator = list.listIterator();
        ListIterator<T> bIterator = list.listIterator(list.size());
        for(int i = 0; i < list.size()/2; i++) {
            T backward = bIterator.previous();
            T forward = fIterator.next();
            bIterator.set(forward);
            fIterator.set(backward);
        }
        return list;
    }
Dakshinamurthy Karra
  • 5,353
  • 1
  • 17
  • 28