Reverse an ArrayList in Java – 在Java中反转数组列表

最后修改: 2022年 6月 1日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

ArrayList is an often-used List implementation in Java.

ArrayList是Java中一个经常使用的List实现。

In this tutorial, we’ll explore how to reverse an ArrayList.

在本教程中,我们将探讨如何反转一个ArrayList

2. Introduction to the Problem

2.对问题的介绍

As usual, let’s understand the problem through an example. Let’s say we have a List of Integer:

按照惯例,让我们通过一个例子来理解这个问题。假设我们有一个ListInteger

​List<Integer> aList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7));

After the reversing, we’re expecting to have the result:

逆转之后,我们期待着得到结果。

List<Integer> EXPECTED = new ArrayList<>(Arrays.asList(7, 6, 5, 4, 3, 2, 1));

So, the requirement looks pretty straightforward. However, the problem may have a couple of variants:

所以,这个要求看起来很直接。然而,这个问题可能有几个变种。

  • Reversing a List in place
  • Reversing a List and returning the result as a new List object

We’ll cover both cases in this tutorial.

我们将在本教程中介绍这两种情况。

The Java standard library has provided a helper method to do the job. We’ll see how we can quickly solve the problem using this method.

Java标准库已经提供了一个辅助方法来完成这项工作。我们将看到我们如何使用这个方法快速解决问题。

Additionally, considering that some of us may be learning Java, we’ll address two interesting but efficient implementations of reversing a List.

此外,考虑到我们中的一些人可能正在学习Java,我们将讨论两个有趣但高效的反转List的实现。

Next, let’s see them in action.

接下来,让我们看看他们的行动。

3. Using the Standard Collections.reverse Method

3.使用标准的Collections.reverse方法

The Java standard library has provided the Collections.reverse method to reverse the order of the elements in the given List.

Java标准库提供了Collections.reverse方法来逆转给定List中元素的顺序。

This convenient method does in-place reversing, which will reverse the order in the original list it received. But, first, let’s create a unit test method to understand it:

这个方便的方法做就地反转,它将反转它收到的原始列表中的顺序。但是,首先,让我们创建一个单元测试方法来了解它。

List<Integer> aList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7));
Collections.reverse(aList);
assertThat(aList).isEqualTo(EXPECTED);

When we execute the test above, it passes. As we’ve seen, we’ve passed the aList object to the reverse method, and then the order of the elements in the aList object gets reversed.

当我们执行上面的测试时,它通过了。正如我们所看到的,我们将aList对象传递给reverse方法,然后aList对象中元素的顺序被颠倒。

In case we don’t want to change the original List, and expect to get a new List object to contain the elements in the reversed order, we can pass a new List object to the reverse method:

如果我们不想改变原来的List,而希望得到一个新的List对象来包含颠倒顺序的元素,我们可以传递一个新的List对象给reverse方法。

List<Integer> originalList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7));
List<Integer> aNewList = new ArrayList<>(originalList);
Collections.reverse(aNewList);

assertThat(aNewList).isNotEqualTo(originalList).isEqualTo(EXPECTED);

In this way, we keep the originalList untouched, and the order of the elements in aNewList is reversed.

这样,我们保持originalList不动,而aNewList中元素的顺序被颠倒。

As we can see from the two examples above, the standard Collections.reverse method is pretty convenient for reversing a List.

从上面的两个例子中我们可以看到,标准的Collections.reverse方法对于反转List是相当方便的。

However, if we’re learning Java, probably, we want to practice implementing a “reverse” method by ourselves.

然而,如果我们正在学习Java,可能,我们想自己练习实现一个 “反向 “方法。

Next, let’s explore a couple of nice implementations: one using recursion and another using a simple loop.

接下来,让我们探索几个不错的实现:一个使用递归,另一个使用简单的循环。

4. Reversing a List Using Recursion

4.使用递归颠倒一个List

First, let’s implement our own list-reverse method using the recursion technique. First, let’s take a look at the implementation:

首先,让我们使用递归技术实现我们自己的列表反转方法。首先,让我们来看看这个实现。

public static <T> void reverseWithRecursion(List<T> list) {
    if (list.size() > 1) {
        T value = list.remove(0);
        reverseWithRecursion(list);
        list.add(value);
    }
}

As we can see, the implementation above looks pretty compact. Now, let’s understand how it works.

我们可以看到,上面的实现看起来很紧凑。现在,让我们了解一下它是如何工作的。

The stop condition in our recursion logic is list.size() <=1. In other words, if the list object is empty or contains only a single element, we stop the recursion.

我们递归逻辑中的停止条件是list.size() <=1。换句话说,如果list对象为空或者只包含一个元素,我们就停止递归

In each recursion call, we execute “T value = list.remove(0)“, popping the first element from the list. It works in this way:

在每个递归调用中,我们执行”T value = list.remove(0)“,从列表中跳出第一个元素。它以这种方式工作。

recursion step 0: value = null, list = (1, 2, 3, ... 7)
   |_ recursion step 1: value = 1, list = (2, 3, 4,...7)
      |_ recursion step 2: value = 2, list = (3, 4, 5, 6, 7)
         |_ recursion step 3: value = 3, list = (4, 5, 6, 7)
            |_ ...
               |_ recursion step 6: value = 6, list = (7) 

As we can see, when the list object contains only one element (7), we stop the recursion and then start executing list.add(value) from the bottom. That is, we first add 6 to the end of the list, then 5, then 4, and so on. In the end, the order of the elements in the list has been in-place reversed. Further, this method runs in linear time.

我们可以看到,当list对象只包含一个元素(7)时,我们停止递归,然后从底部开始执行list.add(value) 。也就是说,我们首先将6添加到列表的末尾,然后是5,然后是4,以此类推。最后,列表中各元素的顺序被原地颠倒了。此外,这个方法在线性时间内运行

Next, let’s create a test to verify if our recursion implementation works as expected:

接下来,让我们创建一个测试来验证我们的递归实现是否像预期的那样工作。

List<Integer> aList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7));
ReverseArrayList.reverseWithRecursion(aList);
assertThat(aList).isEqualTo(EXPECTED);

If we run the test, it passes. So, our recursion implementation solves the problem.

如果我们运行这个测试,它就会通过。所以,我们的递归实现解决了这个问题。

5. Reversing a List Using Iteration

5.使用迭代法逆转List

We’ve just reversed the list using recursion. Alternatively, we can solve the problem using iteration.

我们只是用递归来反转了一下列表。另外,我们也可以用迭代来解决这个问题。

First, let’s have a look at the implementation:

首先,让我们看一下实施情况。

public static <T> void reverseWithLoop(List<T> list) {
    for (int i = 0, j = list.size() - 1; i < j; i++) {
        list.add(i, list.remove(j));
    }
}

As we can see, the iteration implementation is pretty neat as well. However, we have only one for loop, and in the loop body, we have only one single statement.

正如我们所看到的,迭代的实现也是非常整齐的。然而,我们只有一个for循环,而在循环体中,我们只有一个单一的语句。

Next, let’s understand how it works.

接下来,让我们了解一下它是如何工作的。

We defined two pointers, i and j, on the given list. The pointer j always points to the last element in the list. But the point increments from 0 to j-1.

我们在给定的列表上定义了两个指针,ij指针j总是指向列表的最后一个元素。但是指针i从0到j-1递增。

We remove the last element at each iteration step and fill it to the i-th position using list.add(i, list.remove(j)). When i reaches j-1, the loop ends, and we’ve reversed the list:

我们在每个迭代步骤中移除最后一个元素,并使用list.add(i, list.remove(j))将其填充到i-th位置。当i到达j-1时,循环结束,我们已经将列表反转。

Iteration step 0: i = j = null, list = (1, 2, 3,...7)
Iteration step 1: i = 0; j = 6 
                  |_ list.add(0, list.remove(6))
                  |_ list = (7, 1, 2, 3, 4, 5, 6)
Iteration step 2: i = 1; j = 6 
                  |_ list.add(1, list.remove(6))
                  |_ list = (7, 6, 1, 2, 3, 4, 5)
...
Iteration step 5: i = 4; j = 6 
                  |_ list.add(4, list.remove(6))
                  |_ list = (7, 6, 5, 4, 3, 1, 2)
Iteration step 6: i = 5; j = 6 
                  |_ list.add(5, list.remove(6))
                  |_ list = (7, 6, 5, 4, 3, 2, 1)

The method runs in linear time as well.

该方法也能在线性时间内运行

Finally, let’s test our method, and see if it works as expected:

最后,让我们测试一下我们的方法,看看它是否像预期的那样工作。

List<Integer> aList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7));
ReverseArrayList.reverseWithLoop(aList);
assertThat(aList).isEqualTo(EXPECTED);

When we run the test above, it passes.

当我们运行上面的测试时,它通过了。

6. Conclusion

6.结语

In this article, we’ve addressed how to reverse an ArrayList through examples. The standard Collections.reverse method is pretty handy to solve this problem.

在这篇文章中,我们通过实例解决了如何反转ArrayList。标准的Collections.reverse方法对于解决这个问题是相当方便的。

However, if we would like to create our own reversing implementations, we’ve learned two efficient in-place reversing approaches.

然而,如果我们想创建自己的反转实现,我们已经学会了两种有效的就地反转方法。

As usual, the complete code of this article can be found over on GitHub.

像往常一样,本文的完整代码可以在GitHub上找到over