reverse a list of generic typeFinding the largest mirror image of a subset/set of integers present in an array of integersContainer adaptorsEvaluate whether string is in alphabetical order or reverse alphabetical orderReverse each group of k elements in a listJava String Reverse Algorithm which is the most effcient approch?Reverse singly linked listBreaking a 32-bit value into bytes for an ArrayListGeneric Macro Generated Linked List in Ctransform list to arrayLeetCode Reverse Words in a String without using any java library

Is the worst version of the accusations against President Trump impeachable?

What pH range is suitable for cooking on teflon?

Feeling burned-out in PhD. program and thinking about dropping out

What stops one country from issuing another country's passports?

Idiom for "Ahead of its time"

How can I write characters outside a table?

In academic writing why do some recommend to avoid "announcing" the topic?

How did the USSR track Gagarin's Vostok-1 orbital flight? Was tracking capability an issue in the choice of orbit?

How many flight hours do the first retiring A380s have?

Why should interrupts be short in well configured system?

Can you combine DDR3 and DDR4?

Which quantity is mass (tensor, vector or scalar)?

What does "two ells within the selvages" mean in the Magna Carta?

is differential geometry really required to understand anything in algebraic geometry?

80s/90s sitcom with a girl who could stop time and spoke to her dad through a "gem thingy"

Why can I solve an impossible equation using linear algebra?

Pawns pushes in the center

Do any other countries aside from the US have a pledge of allegiance?

80’s or earlier short fantasy about very “sweet” neighbours

Is "to go berserk" used by native speakers or is it obsolete?

Packing disks of infinitesimal diameter on a sphere: the asymptotics of the Tammes problem

United States Towns/States Traversing by Name Puzzle

In C#, is there a way to enforce behavior coupling in interface methods or is the fact that I am trying to do that a design smell?

How to create a new file via touch if it is in a directory which doesn't exist?



reverse a list of generic type


Finding the largest mirror image of a subset/set of integers present in an array of integersContainer adaptorsEvaluate whether string is in alphabetical order or reverse alphabetical orderReverse each group of k elements in a listJava String Reverse Algorithm which is the most effcient approch?Reverse singly linked listBreaking a 32-bit value into bytes for an ArrayListGeneric Macro Generated Linked List in Ctransform list to arrayLeetCode Reverse Words in a String without using any java library






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;









5















$begingroup$



Q: Given a list, reverse the order of its elements (don't use
collections).




Here is my solution:



public static <T> void reverse(List<T> list) 
if (list.size() > 0)
T t;
t = list.get(0);
list.remove(0);
reverse(list);
list.add(t);




  1. I want to know if this is an efficient way of reversing a list

  2. Is this working for every list as input?









share|improve this question











$endgroup$










  • 3




    $begingroup$
    You could compare performance of this against Collection.reverse. My guess is Collection.reverse would be faster
    $endgroup$
    – dustytrash
    Sep 19 at 12:28






  • 2




    $begingroup$
    I'm voting to close this question since it's unclear what the scope of restrictions is concerning the use of collections.
    $endgroup$
    – dfhwze
    Sep 19 at 17:19







  • 2




    $begingroup$
    @Mast I'd say it's not entirely clear whether it's the Collections API, or just collections in general.
    $endgroup$
    – VisualMelon
    Sep 19 at 21:06






  • 1




    $begingroup$
    It's a while since I did Java, but I'm pretty sure List<T> is part of Collections.
    $endgroup$
    – Toby Speight
    Sep 20 at 8:05






  • 1




    $begingroup$
    list.reversed() works just as well, but the question disallows builtin methods, and reverse slicing isn't a method. (and for pure iteration, slicing may even be faster...I'd have to check.)
    $endgroup$
    – Gloweye
    Sep 20 at 10:12

















5















$begingroup$



Q: Given a list, reverse the order of its elements (don't use
collections).




Here is my solution:



public static <T> void reverse(List<T> list) 
if (list.size() > 0)
T t;
t = list.get(0);
list.remove(0);
reverse(list);
list.add(t);




  1. I want to know if this is an efficient way of reversing a list

  2. Is this working for every list as input?









share|improve this question











$endgroup$










  • 3




    $begingroup$
    You could compare performance of this against Collection.reverse. My guess is Collection.reverse would be faster
    $endgroup$
    – dustytrash
    Sep 19 at 12:28






  • 2




    $begingroup$
    I'm voting to close this question since it's unclear what the scope of restrictions is concerning the use of collections.
    $endgroup$
    – dfhwze
    Sep 19 at 17:19







  • 2




    $begingroup$
    @Mast I'd say it's not entirely clear whether it's the Collections API, or just collections in general.
    $endgroup$
    – VisualMelon
    Sep 19 at 21:06






  • 1




    $begingroup$
    It's a while since I did Java, but I'm pretty sure List<T> is part of Collections.
    $endgroup$
    – Toby Speight
    Sep 20 at 8:05






  • 1




    $begingroup$
    list.reversed() works just as well, but the question disallows builtin methods, and reverse slicing isn't a method. (and for pure iteration, slicing may even be faster...I'd have to check.)
    $endgroup$
    – Gloweye
    Sep 20 at 10:12













5













5









5


1



$begingroup$



Q: Given a list, reverse the order of its elements (don't use
collections).




Here is my solution:



public static <T> void reverse(List<T> list) 
if (list.size() > 0)
T t;
t = list.get(0);
list.remove(0);
reverse(list);
list.add(t);




  1. I want to know if this is an efficient way of reversing a list

  2. Is this working for every list as input?









share|improve this question











$endgroup$





Q: Given a list, reverse the order of its elements (don't use
collections).




Here is my solution:



public static <T> void reverse(List<T> list) 
if (list.size() > 0)
T t;
t = list.get(0);
list.remove(0);
reverse(list);
list.add(t);




  1. I want to know if this is an efficient way of reversing a list

  2. Is this working for every list as input?






java reinventing-the-wheel collections






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Sep 19 at 13:29









dfhwze

13.3k3 gold badges26 silver badges95 bronze badges




13.3k3 gold badges26 silver badges95 bronze badges










asked Sep 19 at 12:21









Cristian IacobCristian Iacob

2635 bronze badges




2635 bronze badges










  • 3




    $begingroup$
    You could compare performance of this against Collection.reverse. My guess is Collection.reverse would be faster
    $endgroup$
    – dustytrash
    Sep 19 at 12:28






  • 2




    $begingroup$
    I'm voting to close this question since it's unclear what the scope of restrictions is concerning the use of collections.
    $endgroup$
    – dfhwze
    Sep 19 at 17:19







  • 2




    $begingroup$
    @Mast I'd say it's not entirely clear whether it's the Collections API, or just collections in general.
    $endgroup$
    – VisualMelon
    Sep 19 at 21:06






  • 1




    $begingroup$
    It's a while since I did Java, but I'm pretty sure List<T> is part of Collections.
    $endgroup$
    – Toby Speight
    Sep 20 at 8:05






  • 1




    $begingroup$
    list.reversed() works just as well, but the question disallows builtin methods, and reverse slicing isn't a method. (and for pure iteration, slicing may even be faster...I'd have to check.)
    $endgroup$
    – Gloweye
    Sep 20 at 10:12












  • 3




    $begingroup$
    You could compare performance of this against Collection.reverse. My guess is Collection.reverse would be faster
    $endgroup$
    – dustytrash
    Sep 19 at 12:28






  • 2




    $begingroup$
    I'm voting to close this question since it's unclear what the scope of restrictions is concerning the use of collections.
    $endgroup$
    – dfhwze
    Sep 19 at 17:19







  • 2




    $begingroup$
    @Mast I'd say it's not entirely clear whether it's the Collections API, or just collections in general.
    $endgroup$
    – VisualMelon
    Sep 19 at 21:06






  • 1




    $begingroup$
    It's a while since I did Java, but I'm pretty sure List<T> is part of Collections.
    $endgroup$
    – Toby Speight
    Sep 20 at 8:05






  • 1




    $begingroup$
    list.reversed() works just as well, but the question disallows builtin methods, and reverse slicing isn't a method. (and for pure iteration, slicing may even be faster...I'd have to check.)
    $endgroup$
    – Gloweye
    Sep 20 at 10:12







3




3




$begingroup$
You could compare performance of this against Collection.reverse. My guess is Collection.reverse would be faster
$endgroup$
– dustytrash
Sep 19 at 12:28




$begingroup$
You could compare performance of this against Collection.reverse. My guess is Collection.reverse would be faster
$endgroup$
– dustytrash
Sep 19 at 12:28




2




2




$begingroup$
I'm voting to close this question since it's unclear what the scope of restrictions is concerning the use of collections.
$endgroup$
– dfhwze
Sep 19 at 17:19





$begingroup$
I'm voting to close this question since it's unclear what the scope of restrictions is concerning the use of collections.
$endgroup$
– dfhwze
Sep 19 at 17:19





2




2




$begingroup$
@Mast I'd say it's not entirely clear whether it's the Collections API, or just collections in general.
$endgroup$
– VisualMelon
Sep 19 at 21:06




$begingroup$
@Mast I'd say it's not entirely clear whether it's the Collections API, or just collections in general.
$endgroup$
– VisualMelon
Sep 19 at 21:06




1




1




$begingroup$
It's a while since I did Java, but I'm pretty sure List<T> is part of Collections.
$endgroup$
– Toby Speight
Sep 20 at 8:05




$begingroup$
It's a while since I did Java, but I'm pretty sure List<T> is part of Collections.
$endgroup$
– Toby Speight
Sep 20 at 8:05




1




1




$begingroup$
list.reversed() works just as well, but the question disallows builtin methods, and reverse slicing isn't a method. (and for pure iteration, slicing may even be faster...I'd have to check.)
$endgroup$
– Gloweye
Sep 20 at 10:12




$begingroup$
list.reversed() works just as well, but the question disallows builtin methods, and reverse slicing isn't a method. (and for pure iteration, slicing may even be faster...I'd have to check.)
$endgroup$
– Gloweye
Sep 20 at 10:12










3 Answers
3






active

oldest

votes


















10

















$begingroup$

Java doesn't handle recursion very well. And by not very well I mean it should be avoided almost every time where you cannot limit the depth to something small. To show you how bad it is let's take a look at this simple program:



public static void main(String[] args) 
for(int n = 0; n < 100_000; n+=100)
List<Integer> list = new ArrayList<>();
for(int i = 0; i < n; i++)
list.add(i);

reverse(list);
System.out.println(n);




At some point in the output we can see this:



17800
17900
Exception in thread "main" java.lang.StackOverflowError
at slowness.SlowApp.reverse(SlowApp.java:24)
at slowness.SlowApp.reverse(SlowApp.java:24)


This means that on my machine with default settings I can't even handle a list of 18000 integers. Any list bigger than that just crashes the program.



Is it possible to do it without recursion then?



This has proven a little trickier than I expected when I started writing this answer.



I was thinking of 2 possible approaches.



One is to always update the list in place. Just take the last element from the list and insert it into the correct spot (insert at 0, next insert at 1, next ...). Since we don't know which kind of List we are working with this could be a really expensive operation.



The other approach is to first take a copy of all the elements. Then clear the input list. Reverse the copied elements and insert them back into the input list. The main advantage here is that we can copy them into an array which allows O(1) access to each element even for updating them.



An example implementation is then:



public static <T> void reverse2(List<T> list) 
T[] array = (T[]) list.toArray();

list.clear();

for(int i = 0; i < array.length/2; i++)
T temp = array[i];
array[i] = array[array.length - i-1];
array[array.length-i-1] = temp;


for(T item : array)
list.add(item);




This implementation has no issue with a List of a million Integers.



Edit: just inserting backwards was too obvious after I tried to use list.addAll(aray) which didn't work (needs collection, not an array). I'll leave the current implementation as-is in my answer.



Note that this also isn't the most efficient way. I highly advise you to look at the implementation of the internal Collection.reverse to see a better way.






share|improve this answer












$endgroup$













  • $begingroup$
    Argh, done it again. I keep forgetting List is an interface in Java... @CristianIacob this should probably be the answer, because it isn't wrong and is more general (I'll address that first part in mine presently...)
    $endgroup$
    – VisualMelon
    Sep 19 at 14:15






  • 1




    $begingroup$
    Note that the OP did specify that they don't want to use other collections.
    $endgroup$
    – VisualMelon
    Sep 19 at 14:18






  • 2




    $begingroup$
    @VisualMelon I interpreted that as "don't use collections.reverse, implement it yourself". Otherwise you couldn't even use add or remove
    $endgroup$
    – Imus
    Sep 19 at 14:23











  • $begingroup$
    Is for (int i = array.length - 1; i >= 0; i--) list.add(array[i]); (backwards iteration + add) different than the 1.5x iteration?
    $endgroup$
    – Ivan García Topete
    Sep 20 at 0:41







  • 2




    $begingroup$
    why do you bother reversing the array, rather than just inserting in reverse order?
    $endgroup$
    – njzk2
    Sep 20 at 5:54


















10

















$begingroup$

No and no. This is a very inefficient way to reverse, for example, a dynamic array based list (it's a different story with a linked list). With a dynamic array based (e.g. ArrayList) The remove(0) operation will require moving every other element in the list (linear in the length), so the whole method is quadratic in the total length of the list. It also requires a linear number of stack frames, which are actually pretty expensive and if you ask for too many the program will crash, which means this method will not work for long lists.



An efficient solution would work in linear time with a constant space requirement.




When thinking about inputs, it's important to also consider null as a possible input. The deficient spec does not indicate what should be done with a null input, which means you have had to make a decision, and that decision should be documented. The 'easy' (and often best) option is to explicitly test for a null input and throw an IllegalArgumentException exception, so that anyone using your method receives a useful error message. You could argue that your code should do nothing with a null, but that's a bit iffy, because the spec doesn't qualify the behaviour, and that would 'silently' fail if someone passed it a null incorrectly: throwing an exception forces any unexpected usage to be address directly, which may or may not prompt a decision change, which makes it a good 'default' choice.




There is no need here to pre-declare t: just declare and assign it in one go:



T t = list.get(0);


This makes it easier to find out what it means. You could also make it final in this case, so that it is entirely clear that it is only assigned once, which makes it that little bit easier to reason about the code.




When writing recursive code like this, it can pay select the 'most ideal' base case. In this instance, any list of length no more than 1 is already reversed, so you could change the if condition to list.size() > 1. This doesn't change the complexity, but is something of which to be aware.






share|improve this answer












$endgroup$





















    1

















    $begingroup$

    Already answered, but as task, one probably fares better with not introducing too many extra structures.



    I'll immediately give an iterative version. It shows some improvements that could also be made to your recursive solution.



    The recursive solution is fine, though seemingly needing a call stack the size of the list. However tail-recursion can be optimized by a good compiler (made iterative).
    The iterative version needs an extra variable to hold a temporary result (the recursive call's result).



    public static <T> void reverse(List<T> list) 
    if (list.size() > 1) // Not needed, heuristic optimisation
    //List<T> reversed = new ArrayList<>(list.size());
    List<T> reversed = new LinkedList<>();
    while (!list.isEmpty()) // Or list.size() > 1
    T t = list.remove(0);
    reversed.add(t);

    list.addAll(reversed);





    I want to know if this is an efficient way of reversing a list




    Already answered by others, but it could be astonishly good.
    Nicer would be if the list was not modified in-situ, but substituted by a new List,
    as then the list.addAll(reversed) could be exchanged for return reversed;.




    Is this working for every list as input?




    Yes, though the list must not be operated upon at the same time.



    There are some lists, immutable lists (that are not allowed to be changed) or lists that are backed by arrays (strudcturally immutable), that will throw an error.






    share|improve this answer










    $endgroup$















      Your Answer






      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "196"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );














      draft saved

      draft discarded
















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f229308%2freverse-a-list-of-generic-type%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown


























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      10

















      $begingroup$

      Java doesn't handle recursion very well. And by not very well I mean it should be avoided almost every time where you cannot limit the depth to something small. To show you how bad it is let's take a look at this simple program:



      public static void main(String[] args) 
      for(int n = 0; n < 100_000; n+=100)
      List<Integer> list = new ArrayList<>();
      for(int i = 0; i < n; i++)
      list.add(i);

      reverse(list);
      System.out.println(n);




      At some point in the output we can see this:



      17800
      17900
      Exception in thread "main" java.lang.StackOverflowError
      at slowness.SlowApp.reverse(SlowApp.java:24)
      at slowness.SlowApp.reverse(SlowApp.java:24)


      This means that on my machine with default settings I can't even handle a list of 18000 integers. Any list bigger than that just crashes the program.



      Is it possible to do it without recursion then?



      This has proven a little trickier than I expected when I started writing this answer.



      I was thinking of 2 possible approaches.



      One is to always update the list in place. Just take the last element from the list and insert it into the correct spot (insert at 0, next insert at 1, next ...). Since we don't know which kind of List we are working with this could be a really expensive operation.



      The other approach is to first take a copy of all the elements. Then clear the input list. Reverse the copied elements and insert them back into the input list. The main advantage here is that we can copy them into an array which allows O(1) access to each element even for updating them.



      An example implementation is then:



      public static <T> void reverse2(List<T> list) 
      T[] array = (T[]) list.toArray();

      list.clear();

      for(int i = 0; i < array.length/2; i++)
      T temp = array[i];
      array[i] = array[array.length - i-1];
      array[array.length-i-1] = temp;


      for(T item : array)
      list.add(item);




      This implementation has no issue with a List of a million Integers.



      Edit: just inserting backwards was too obvious after I tried to use list.addAll(aray) which didn't work (needs collection, not an array). I'll leave the current implementation as-is in my answer.



      Note that this also isn't the most efficient way. I highly advise you to look at the implementation of the internal Collection.reverse to see a better way.






      share|improve this answer












      $endgroup$













      • $begingroup$
        Argh, done it again. I keep forgetting List is an interface in Java... @CristianIacob this should probably be the answer, because it isn't wrong and is more general (I'll address that first part in mine presently...)
        $endgroup$
        – VisualMelon
        Sep 19 at 14:15






      • 1




        $begingroup$
        Note that the OP did specify that they don't want to use other collections.
        $endgroup$
        – VisualMelon
        Sep 19 at 14:18






      • 2




        $begingroup$
        @VisualMelon I interpreted that as "don't use collections.reverse, implement it yourself". Otherwise you couldn't even use add or remove
        $endgroup$
        – Imus
        Sep 19 at 14:23











      • $begingroup$
        Is for (int i = array.length - 1; i >= 0; i--) list.add(array[i]); (backwards iteration + add) different than the 1.5x iteration?
        $endgroup$
        – Ivan García Topete
        Sep 20 at 0:41







      • 2




        $begingroup$
        why do you bother reversing the array, rather than just inserting in reverse order?
        $endgroup$
        – njzk2
        Sep 20 at 5:54















      10

















      $begingroup$

      Java doesn't handle recursion very well. And by not very well I mean it should be avoided almost every time where you cannot limit the depth to something small. To show you how bad it is let's take a look at this simple program:



      public static void main(String[] args) 
      for(int n = 0; n < 100_000; n+=100)
      List<Integer> list = new ArrayList<>();
      for(int i = 0; i < n; i++)
      list.add(i);

      reverse(list);
      System.out.println(n);




      At some point in the output we can see this:



      17800
      17900
      Exception in thread "main" java.lang.StackOverflowError
      at slowness.SlowApp.reverse(SlowApp.java:24)
      at slowness.SlowApp.reverse(SlowApp.java:24)


      This means that on my machine with default settings I can't even handle a list of 18000 integers. Any list bigger than that just crashes the program.



      Is it possible to do it without recursion then?



      This has proven a little trickier than I expected when I started writing this answer.



      I was thinking of 2 possible approaches.



      One is to always update the list in place. Just take the last element from the list and insert it into the correct spot (insert at 0, next insert at 1, next ...). Since we don't know which kind of List we are working with this could be a really expensive operation.



      The other approach is to first take a copy of all the elements. Then clear the input list. Reverse the copied elements and insert them back into the input list. The main advantage here is that we can copy them into an array which allows O(1) access to each element even for updating them.



      An example implementation is then:



      public static <T> void reverse2(List<T> list) 
      T[] array = (T[]) list.toArray();

      list.clear();

      for(int i = 0; i < array.length/2; i++)
      T temp = array[i];
      array[i] = array[array.length - i-1];
      array[array.length-i-1] = temp;


      for(T item : array)
      list.add(item);




      This implementation has no issue with a List of a million Integers.



      Edit: just inserting backwards was too obvious after I tried to use list.addAll(aray) which didn't work (needs collection, not an array). I'll leave the current implementation as-is in my answer.



      Note that this also isn't the most efficient way. I highly advise you to look at the implementation of the internal Collection.reverse to see a better way.






      share|improve this answer












      $endgroup$













      • $begingroup$
        Argh, done it again. I keep forgetting List is an interface in Java... @CristianIacob this should probably be the answer, because it isn't wrong and is more general (I'll address that first part in mine presently...)
        $endgroup$
        – VisualMelon
        Sep 19 at 14:15






      • 1




        $begingroup$
        Note that the OP did specify that they don't want to use other collections.
        $endgroup$
        – VisualMelon
        Sep 19 at 14:18






      • 2




        $begingroup$
        @VisualMelon I interpreted that as "don't use collections.reverse, implement it yourself". Otherwise you couldn't even use add or remove
        $endgroup$
        – Imus
        Sep 19 at 14:23











      • $begingroup$
        Is for (int i = array.length - 1; i >= 0; i--) list.add(array[i]); (backwards iteration + add) different than the 1.5x iteration?
        $endgroup$
        – Ivan García Topete
        Sep 20 at 0:41







      • 2




        $begingroup$
        why do you bother reversing the array, rather than just inserting in reverse order?
        $endgroup$
        – njzk2
        Sep 20 at 5:54













      10















      10











      10







      $begingroup$

      Java doesn't handle recursion very well. And by not very well I mean it should be avoided almost every time where you cannot limit the depth to something small. To show you how bad it is let's take a look at this simple program:



      public static void main(String[] args) 
      for(int n = 0; n < 100_000; n+=100)
      List<Integer> list = new ArrayList<>();
      for(int i = 0; i < n; i++)
      list.add(i);

      reverse(list);
      System.out.println(n);




      At some point in the output we can see this:



      17800
      17900
      Exception in thread "main" java.lang.StackOverflowError
      at slowness.SlowApp.reverse(SlowApp.java:24)
      at slowness.SlowApp.reverse(SlowApp.java:24)


      This means that on my machine with default settings I can't even handle a list of 18000 integers. Any list bigger than that just crashes the program.



      Is it possible to do it without recursion then?



      This has proven a little trickier than I expected when I started writing this answer.



      I was thinking of 2 possible approaches.



      One is to always update the list in place. Just take the last element from the list and insert it into the correct spot (insert at 0, next insert at 1, next ...). Since we don't know which kind of List we are working with this could be a really expensive operation.



      The other approach is to first take a copy of all the elements. Then clear the input list. Reverse the copied elements and insert them back into the input list. The main advantage here is that we can copy them into an array which allows O(1) access to each element even for updating them.



      An example implementation is then:



      public static <T> void reverse2(List<T> list) 
      T[] array = (T[]) list.toArray();

      list.clear();

      for(int i = 0; i < array.length/2; i++)
      T temp = array[i];
      array[i] = array[array.length - i-1];
      array[array.length-i-1] = temp;


      for(T item : array)
      list.add(item);




      This implementation has no issue with a List of a million Integers.



      Edit: just inserting backwards was too obvious after I tried to use list.addAll(aray) which didn't work (needs collection, not an array). I'll leave the current implementation as-is in my answer.



      Note that this also isn't the most efficient way. I highly advise you to look at the implementation of the internal Collection.reverse to see a better way.






      share|improve this answer












      $endgroup$



      Java doesn't handle recursion very well. And by not very well I mean it should be avoided almost every time where you cannot limit the depth to something small. To show you how bad it is let's take a look at this simple program:



      public static void main(String[] args) 
      for(int n = 0; n < 100_000; n+=100)
      List<Integer> list = new ArrayList<>();
      for(int i = 0; i < n; i++)
      list.add(i);

      reverse(list);
      System.out.println(n);




      At some point in the output we can see this:



      17800
      17900
      Exception in thread "main" java.lang.StackOverflowError
      at slowness.SlowApp.reverse(SlowApp.java:24)
      at slowness.SlowApp.reverse(SlowApp.java:24)


      This means that on my machine with default settings I can't even handle a list of 18000 integers. Any list bigger than that just crashes the program.



      Is it possible to do it without recursion then?



      This has proven a little trickier than I expected when I started writing this answer.



      I was thinking of 2 possible approaches.



      One is to always update the list in place. Just take the last element from the list and insert it into the correct spot (insert at 0, next insert at 1, next ...). Since we don't know which kind of List we are working with this could be a really expensive operation.



      The other approach is to first take a copy of all the elements. Then clear the input list. Reverse the copied elements and insert them back into the input list. The main advantage here is that we can copy them into an array which allows O(1) access to each element even for updating them.



      An example implementation is then:



      public static <T> void reverse2(List<T> list) 
      T[] array = (T[]) list.toArray();

      list.clear();

      for(int i = 0; i < array.length/2; i++)
      T temp = array[i];
      array[i] = array[array.length - i-1];
      array[array.length-i-1] = temp;


      for(T item : array)
      list.add(item);




      This implementation has no issue with a List of a million Integers.



      Edit: just inserting backwards was too obvious after I tried to use list.addAll(aray) which didn't work (needs collection, not an array). I'll leave the current implementation as-is in my answer.



      Note that this also isn't the most efficient way. I highly advise you to look at the implementation of the internal Collection.reverse to see a better way.







      share|improve this answer















      share|improve this answer




      share|improve this answer








      edited Sep 20 at 6:04

























      answered Sep 19 at 14:10









      ImusImus

      3,8933 silver badges25 bronze badges




      3,8933 silver badges25 bronze badges














      • $begingroup$
        Argh, done it again. I keep forgetting List is an interface in Java... @CristianIacob this should probably be the answer, because it isn't wrong and is more general (I'll address that first part in mine presently...)
        $endgroup$
        – VisualMelon
        Sep 19 at 14:15






      • 1




        $begingroup$
        Note that the OP did specify that they don't want to use other collections.
        $endgroup$
        – VisualMelon
        Sep 19 at 14:18






      • 2




        $begingroup$
        @VisualMelon I interpreted that as "don't use collections.reverse, implement it yourself". Otherwise you couldn't even use add or remove
        $endgroup$
        – Imus
        Sep 19 at 14:23











      • $begingroup$
        Is for (int i = array.length - 1; i >= 0; i--) list.add(array[i]); (backwards iteration + add) different than the 1.5x iteration?
        $endgroup$
        – Ivan García Topete
        Sep 20 at 0:41







      • 2




        $begingroup$
        why do you bother reversing the array, rather than just inserting in reverse order?
        $endgroup$
        – njzk2
        Sep 20 at 5:54
















      • $begingroup$
        Argh, done it again. I keep forgetting List is an interface in Java... @CristianIacob this should probably be the answer, because it isn't wrong and is more general (I'll address that first part in mine presently...)
        $endgroup$
        – VisualMelon
        Sep 19 at 14:15






      • 1




        $begingroup$
        Note that the OP did specify that they don't want to use other collections.
        $endgroup$
        – VisualMelon
        Sep 19 at 14:18






      • 2




        $begingroup$
        @VisualMelon I interpreted that as "don't use collections.reverse, implement it yourself". Otherwise you couldn't even use add or remove
        $endgroup$
        – Imus
        Sep 19 at 14:23











      • $begingroup$
        Is for (int i = array.length - 1; i >= 0; i--) list.add(array[i]); (backwards iteration + add) different than the 1.5x iteration?
        $endgroup$
        – Ivan García Topete
        Sep 20 at 0:41







      • 2




        $begingroup$
        why do you bother reversing the array, rather than just inserting in reverse order?
        $endgroup$
        – njzk2
        Sep 20 at 5:54















      $begingroup$
      Argh, done it again. I keep forgetting List is an interface in Java... @CristianIacob this should probably be the answer, because it isn't wrong and is more general (I'll address that first part in mine presently...)
      $endgroup$
      – VisualMelon
      Sep 19 at 14:15




      $begingroup$
      Argh, done it again. I keep forgetting List is an interface in Java... @CristianIacob this should probably be the answer, because it isn't wrong and is more general (I'll address that first part in mine presently...)
      $endgroup$
      – VisualMelon
      Sep 19 at 14:15




      1




      1




      $begingroup$
      Note that the OP did specify that they don't want to use other collections.
      $endgroup$
      – VisualMelon
      Sep 19 at 14:18




      $begingroup$
      Note that the OP did specify that they don't want to use other collections.
      $endgroup$
      – VisualMelon
      Sep 19 at 14:18




      2




      2




      $begingroup$
      @VisualMelon I interpreted that as "don't use collections.reverse, implement it yourself". Otherwise you couldn't even use add or remove
      $endgroup$
      – Imus
      Sep 19 at 14:23





      $begingroup$
      @VisualMelon I interpreted that as "don't use collections.reverse, implement it yourself". Otherwise you couldn't even use add or remove
      $endgroup$
      – Imus
      Sep 19 at 14:23













      $begingroup$
      Is for (int i = array.length - 1; i >= 0; i--) list.add(array[i]); (backwards iteration + add) different than the 1.5x iteration?
      $endgroup$
      – Ivan García Topete
      Sep 20 at 0:41





      $begingroup$
      Is for (int i = array.length - 1; i >= 0; i--) list.add(array[i]); (backwards iteration + add) different than the 1.5x iteration?
      $endgroup$
      – Ivan García Topete
      Sep 20 at 0:41





      2




      2




      $begingroup$
      why do you bother reversing the array, rather than just inserting in reverse order?
      $endgroup$
      – njzk2
      Sep 20 at 5:54




      $begingroup$
      why do you bother reversing the array, rather than just inserting in reverse order?
      $endgroup$
      – njzk2
      Sep 20 at 5:54













      10

















      $begingroup$

      No and no. This is a very inefficient way to reverse, for example, a dynamic array based list (it's a different story with a linked list). With a dynamic array based (e.g. ArrayList) The remove(0) operation will require moving every other element in the list (linear in the length), so the whole method is quadratic in the total length of the list. It also requires a linear number of stack frames, which are actually pretty expensive and if you ask for too many the program will crash, which means this method will not work for long lists.



      An efficient solution would work in linear time with a constant space requirement.




      When thinking about inputs, it's important to also consider null as a possible input. The deficient spec does not indicate what should be done with a null input, which means you have had to make a decision, and that decision should be documented. The 'easy' (and often best) option is to explicitly test for a null input and throw an IllegalArgumentException exception, so that anyone using your method receives a useful error message. You could argue that your code should do nothing with a null, but that's a bit iffy, because the spec doesn't qualify the behaviour, and that would 'silently' fail if someone passed it a null incorrectly: throwing an exception forces any unexpected usage to be address directly, which may or may not prompt a decision change, which makes it a good 'default' choice.




      There is no need here to pre-declare t: just declare and assign it in one go:



      T t = list.get(0);


      This makes it easier to find out what it means. You could also make it final in this case, so that it is entirely clear that it is only assigned once, which makes it that little bit easier to reason about the code.




      When writing recursive code like this, it can pay select the 'most ideal' base case. In this instance, any list of length no more than 1 is already reversed, so you could change the if condition to list.size() > 1. This doesn't change the complexity, but is something of which to be aware.






      share|improve this answer












      $endgroup$


















        10

















        $begingroup$

        No and no. This is a very inefficient way to reverse, for example, a dynamic array based list (it's a different story with a linked list). With a dynamic array based (e.g. ArrayList) The remove(0) operation will require moving every other element in the list (linear in the length), so the whole method is quadratic in the total length of the list. It also requires a linear number of stack frames, which are actually pretty expensive and if you ask for too many the program will crash, which means this method will not work for long lists.



        An efficient solution would work in linear time with a constant space requirement.




        When thinking about inputs, it's important to also consider null as a possible input. The deficient spec does not indicate what should be done with a null input, which means you have had to make a decision, and that decision should be documented. The 'easy' (and often best) option is to explicitly test for a null input and throw an IllegalArgumentException exception, so that anyone using your method receives a useful error message. You could argue that your code should do nothing with a null, but that's a bit iffy, because the spec doesn't qualify the behaviour, and that would 'silently' fail if someone passed it a null incorrectly: throwing an exception forces any unexpected usage to be address directly, which may or may not prompt a decision change, which makes it a good 'default' choice.




        There is no need here to pre-declare t: just declare and assign it in one go:



        T t = list.get(0);


        This makes it easier to find out what it means. You could also make it final in this case, so that it is entirely clear that it is only assigned once, which makes it that little bit easier to reason about the code.




        When writing recursive code like this, it can pay select the 'most ideal' base case. In this instance, any list of length no more than 1 is already reversed, so you could change the if condition to list.size() > 1. This doesn't change the complexity, but is something of which to be aware.






        share|improve this answer












        $endgroup$
















          10















          10











          10







          $begingroup$

          No and no. This is a very inefficient way to reverse, for example, a dynamic array based list (it's a different story with a linked list). With a dynamic array based (e.g. ArrayList) The remove(0) operation will require moving every other element in the list (linear in the length), so the whole method is quadratic in the total length of the list. It also requires a linear number of stack frames, which are actually pretty expensive and if you ask for too many the program will crash, which means this method will not work for long lists.



          An efficient solution would work in linear time with a constant space requirement.




          When thinking about inputs, it's important to also consider null as a possible input. The deficient spec does not indicate what should be done with a null input, which means you have had to make a decision, and that decision should be documented. The 'easy' (and often best) option is to explicitly test for a null input and throw an IllegalArgumentException exception, so that anyone using your method receives a useful error message. You could argue that your code should do nothing with a null, but that's a bit iffy, because the spec doesn't qualify the behaviour, and that would 'silently' fail if someone passed it a null incorrectly: throwing an exception forces any unexpected usage to be address directly, which may or may not prompt a decision change, which makes it a good 'default' choice.




          There is no need here to pre-declare t: just declare and assign it in one go:



          T t = list.get(0);


          This makes it easier to find out what it means. You could also make it final in this case, so that it is entirely clear that it is only assigned once, which makes it that little bit easier to reason about the code.




          When writing recursive code like this, it can pay select the 'most ideal' base case. In this instance, any list of length no more than 1 is already reversed, so you could change the if condition to list.size() > 1. This doesn't change the complexity, but is something of which to be aware.






          share|improve this answer












          $endgroup$



          No and no. This is a very inefficient way to reverse, for example, a dynamic array based list (it's a different story with a linked list). With a dynamic array based (e.g. ArrayList) The remove(0) operation will require moving every other element in the list (linear in the length), so the whole method is quadratic in the total length of the list. It also requires a linear number of stack frames, which are actually pretty expensive and if you ask for too many the program will crash, which means this method will not work for long lists.



          An efficient solution would work in linear time with a constant space requirement.




          When thinking about inputs, it's important to also consider null as a possible input. The deficient spec does not indicate what should be done with a null input, which means you have had to make a decision, and that decision should be documented. The 'easy' (and often best) option is to explicitly test for a null input and throw an IllegalArgumentException exception, so that anyone using your method receives a useful error message. You could argue that your code should do nothing with a null, but that's a bit iffy, because the spec doesn't qualify the behaviour, and that would 'silently' fail if someone passed it a null incorrectly: throwing an exception forces any unexpected usage to be address directly, which may or may not prompt a decision change, which makes it a good 'default' choice.




          There is no need here to pre-declare t: just declare and assign it in one go:



          T t = list.get(0);


          This makes it easier to find out what it means. You could also make it final in this case, so that it is entirely clear that it is only assigned once, which makes it that little bit easier to reason about the code.




          When writing recursive code like this, it can pay select the 'most ideal' base case. In this instance, any list of length no more than 1 is already reversed, so you could change the if condition to list.size() > 1. This doesn't change the complexity, but is something of which to be aware.







          share|improve this answer















          share|improve this answer




          share|improve this answer








          edited Sep 19 at 14:16

























          answered Sep 19 at 12:44









          VisualMelonVisualMelon

          6,86015 silver badges44 bronze badges




          6,86015 silver badges44 bronze badges
























              1

















              $begingroup$

              Already answered, but as task, one probably fares better with not introducing too many extra structures.



              I'll immediately give an iterative version. It shows some improvements that could also be made to your recursive solution.



              The recursive solution is fine, though seemingly needing a call stack the size of the list. However tail-recursion can be optimized by a good compiler (made iterative).
              The iterative version needs an extra variable to hold a temporary result (the recursive call's result).



              public static <T> void reverse(List<T> list) 
              if (list.size() > 1) // Not needed, heuristic optimisation
              //List<T> reversed = new ArrayList<>(list.size());
              List<T> reversed = new LinkedList<>();
              while (!list.isEmpty()) // Or list.size() > 1
              T t = list.remove(0);
              reversed.add(t);

              list.addAll(reversed);





              I want to know if this is an efficient way of reversing a list




              Already answered by others, but it could be astonishly good.
              Nicer would be if the list was not modified in-situ, but substituted by a new List,
              as then the list.addAll(reversed) could be exchanged for return reversed;.




              Is this working for every list as input?




              Yes, though the list must not be operated upon at the same time.



              There are some lists, immutable lists (that are not allowed to be changed) or lists that are backed by arrays (strudcturally immutable), that will throw an error.






              share|improve this answer










              $endgroup$


















                1

















                $begingroup$

                Already answered, but as task, one probably fares better with not introducing too many extra structures.



                I'll immediately give an iterative version. It shows some improvements that could also be made to your recursive solution.



                The recursive solution is fine, though seemingly needing a call stack the size of the list. However tail-recursion can be optimized by a good compiler (made iterative).
                The iterative version needs an extra variable to hold a temporary result (the recursive call's result).



                public static <T> void reverse(List<T> list) 
                if (list.size() > 1) // Not needed, heuristic optimisation
                //List<T> reversed = new ArrayList<>(list.size());
                List<T> reversed = new LinkedList<>();
                while (!list.isEmpty()) // Or list.size() > 1
                T t = list.remove(0);
                reversed.add(t);

                list.addAll(reversed);





                I want to know if this is an efficient way of reversing a list




                Already answered by others, but it could be astonishly good.
                Nicer would be if the list was not modified in-situ, but substituted by a new List,
                as then the list.addAll(reversed) could be exchanged for return reversed;.




                Is this working for every list as input?




                Yes, though the list must not be operated upon at the same time.



                There are some lists, immutable lists (that are not allowed to be changed) or lists that are backed by arrays (strudcturally immutable), that will throw an error.






                share|improve this answer










                $endgroup$
















                  1















                  1











                  1







                  $begingroup$

                  Already answered, but as task, one probably fares better with not introducing too many extra structures.



                  I'll immediately give an iterative version. It shows some improvements that could also be made to your recursive solution.



                  The recursive solution is fine, though seemingly needing a call stack the size of the list. However tail-recursion can be optimized by a good compiler (made iterative).
                  The iterative version needs an extra variable to hold a temporary result (the recursive call's result).



                  public static <T> void reverse(List<T> list) 
                  if (list.size() > 1) // Not needed, heuristic optimisation
                  //List<T> reversed = new ArrayList<>(list.size());
                  List<T> reversed = new LinkedList<>();
                  while (!list.isEmpty()) // Or list.size() > 1
                  T t = list.remove(0);
                  reversed.add(t);

                  list.addAll(reversed);





                  I want to know if this is an efficient way of reversing a list




                  Already answered by others, but it could be astonishly good.
                  Nicer would be if the list was not modified in-situ, but substituted by a new List,
                  as then the list.addAll(reversed) could be exchanged for return reversed;.




                  Is this working for every list as input?




                  Yes, though the list must not be operated upon at the same time.



                  There are some lists, immutable lists (that are not allowed to be changed) or lists that are backed by arrays (strudcturally immutable), that will throw an error.






                  share|improve this answer










                  $endgroup$



                  Already answered, but as task, one probably fares better with not introducing too many extra structures.



                  I'll immediately give an iterative version. It shows some improvements that could also be made to your recursive solution.



                  The recursive solution is fine, though seemingly needing a call stack the size of the list. However tail-recursion can be optimized by a good compiler (made iterative).
                  The iterative version needs an extra variable to hold a temporary result (the recursive call's result).



                  public static <T> void reverse(List<T> list) 
                  if (list.size() > 1) // Not needed, heuristic optimisation
                  //List<T> reversed = new ArrayList<>(list.size());
                  List<T> reversed = new LinkedList<>();
                  while (!list.isEmpty()) // Or list.size() > 1
                  T t = list.remove(0);
                  reversed.add(t);

                  list.addAll(reversed);





                  I want to know if this is an efficient way of reversing a list




                  Already answered by others, but it could be astonishly good.
                  Nicer would be if the list was not modified in-situ, but substituted by a new List,
                  as then the list.addAll(reversed) could be exchanged for return reversed;.




                  Is this working for every list as input?




                  Yes, though the list must not be operated upon at the same time.



                  There are some lists, immutable lists (that are not allowed to be changed) or lists that are backed by arrays (strudcturally immutable), that will throw an error.







                  share|improve this answer













                  share|improve this answer




                  share|improve this answer










                  answered Sep 20 at 11:03









                  Joop EggenJoop Eggen

                  1,5999 silver badges14 bronze badges




                  1,5999 silver badges14 bronze badges































                      draft saved

                      draft discarded















































                      Thanks for contributing an answer to Code Review Stack Exchange!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      Use MathJax to format equations. MathJax reference.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f229308%2freverse-a-list-of-generic-type%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown









                      Popular posts from this blog

                      Tamil (spriik) Luke uk diar | Nawigatjuun

                      Align equal signs while including text over equalitiesAMS align: left aligned text/math plus multicolumn alignmentMultiple alignmentsAligning equations in multiple placesNumbering and aligning an equation with multiple columnsHow to align one equation with another multline equationUsing \ in environments inside the begintabularxNumber equations and preserving alignment of equal signsHow can I align equations to the left and to the right?Double equation alignment problem within align enviromentAligned within align: Why are they right-aligned?

                      Training a classifier when some of the features are unknownWhy does Gradient Boosting regression predict negative values when there are no negative y-values in my training set?How to improve an existing (trained) classifier?What is effect when I set up some self defined predisctor variables?Why Matlab neural network classification returns decimal values on prediction dataset?Fitting and transforming text data in training, testing, and validation setsHow to quantify the performance of the classifier (multi-class SVM) using the test data?How do I control for some patients providing multiple samples in my training data?Training and Test setTraining a convolutional neural network for image denoising in MatlabShouldn't an autoencoder with #(neurons in hidden layer) = #(neurons in input layer) be “perfect”?