【问题标题】:Reversing a List via ListIterator通过 ListIterator 反转列表
【发布时间】:2018-10-14 21:00:03
【问题描述】:

我有一个任务,我必须用一个或多个 ListIterators 反转一个列表。我不允许使用方法collections.reverse() 或其他类似的方法。我也不允许开辟新的领域。我也不能只使用新列表。必须更改输入!

这是我到目前为止所得到的。但是输入没有改变:

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;
}

【问题讨论】:

  • 必须使用iterator吗?一个简单的循环就足够了。
  • 是的,我必须使用迭代器。

标签: java list collections iterator


【解决方案1】:

这是一种递归解决问题的方法:

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);
    }
}

这使用一个迭代器一直递归到列表的末尾,然后在返回调用堆栈的途中,它使用第二个迭代器在列表中向前运行,沿途设置元素。这不使用第二个列表,尽管您可以说这是作弊,因为列表的全部内容都存储在调用堆栈中......

这是一种非递归方法,使用与其他人展示的类似的技术。不过,我认为循环和交换逻辑要简单一些:

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);
    }
}

我已经避免使用Collections.swap,因为这似乎是问题的一个限制(但如果列表是LinkedList,你不会想用它来交换元素(但你几乎不应该使用LinkedList 反正))。

【讨论】:

  • 递归解决方案看起来很聪明:)
【解决方案2】:

在这个问题上使用ListIterator&lt;T&gt; 很奇怪,但是这里是迭代列表两次的解决方案。这里我们不使用Collections 类:

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;
}

编辑:我犯了一个错误。 ListIterator&lt;E&gt; listIterator(int index) 方法提供了一个从索引开始的 ListIterator。既然从头开始,就可以迭代一次,将所有元素添加到新的List中。


Edit2:在不创建新列表的情况下,我发现您必须迭代列表的一半并从末尾/开头到中间获取项目并交换它们。

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;
}

【讨论】:

  • 指定不允许创建新列表。所以从我的角度来看,它基本上是在强迫一个人进入swap
【解决方案3】:

使用迭代器执行此操作是一种奇怪的方式,因为 Collections.swap 方法(这可能是获得您需要实现的目标的最简单方法)专门要求索引。因此,首先使用那些将是要走的路。尽管如此,您显然也可以使用迭代器来做到这一点。这可能如下所示:

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;
}

您首先设置迭代器。一个从列表的开头开始,一个在末尾。

然后你循环只要it.nextIndex() - itR.previousIndex() &lt; 0。这基本上是将两个迭代器移动到 List 的中心而不交叉,因此您不会交换回已经交换的元素。

最后,您只需交换相应索引处的元素并移动迭代器。

更新

正如您所指定的,您不能直接使用Collections.swap(无论出于何种原因),您显然也可以重新发明轮子并重写该方法的作用。

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;
}

在不使用(老实说在所有情况下都是首选的)Collections.swap 方法的情况下执行完全相同的操作。

【讨论】:

  • 我知道用迭代器做这件事是一种奇怪的方式。但是该任务旨在学习如何使用迭代器,因此不允许仅将列表与 Collections.swap 交换。在您的帮助下,我已经取得了一些进展,但我的代码仍然存在一些问题。
  • @AntonMoog 我已经更新了我的答案。我不完全知道这如何教会你更多关于迭代器的知识,但我想任务就是任务。
【解决方案4】:

这样的?

 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;
    }

【讨论】:

    猜你喜欢
    • 2021-10-24
    • 2016-02-15
    • 2015-09-30
    • 1970-01-01
    • 2020-02-19
    • 2015-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多