在Java中反转链表

时间:2014-02-07 04:04:31

标签: java recursion time-complexity

我尝试使用递归来反转链表,但是我得到了奇怪的结果,以下是我的代码:

import java.util.LinkedList;
import java.util.List;

/**
 * Created by liqiushi on 2/6/14.
 */
public class ReverseLinkedList {
    public static void main(String[] args) {
        List<Integer> list = new LinkedList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);

        reverse(list, 0);
        for (int i : list) {
            System.out.println(i);
        }
    }

    private static void reverse(List<Integer> list, int index) {
        if (list == null)
            return;

        if (index == 5) {
            return;
        }
        int currentVal = list.get(0);
        list = list.subList(1, list.size());
        index += 1;
        reverse(list, index);

        list.add(currentVal);
    }
}

执行的结果是:1 2 3 4 5 5 4 3 2 1,我哪里出错了?

P.S。我试图分析这个算法的时间复杂度,我认为它应该是O(n)因为它只是递归4次,就像一棵树,其中每个节点只有一个左或右孩子,如果我错了就纠正我。

3 个答案:

答案 0 :(得分:2)

基本上,如果您想替换元素(而不是添加),则不应使用List#add

您可以执行以下操作:

private static void reverse(final List<Integer> list, final int index) {
    if (index >= list.size()) {
        return;
    }

    final int currentVal = list.get(index);
    reverse(list, index + 1);
    list.set(list.size() - 1 - index, currentVal);
}

虽然效率不高LinkedList,但它会起作用。 :)


另一方面,如果您真的希望您的方法按add - 元素运行到新的List,那么它必须返回 { {1}}因此,其签名应为:

List

基本上,在这种情况下,你会:

  • 创建返回新<{1}},当反向没有任何内容时,
  • 以递归方式反转给定private static List<Integer> reverse(final List<Integer> list, final int index) 的其余部分,最后
  • 返回
  • 之前添加List末尾的当前元素。

例如:

List

(如果您这样做,请不要忘记在List方法中迭代private static List<Integer> reverse(final List<Integer> list, final int index) { if (index >= list.size()) { return new LinkedList<>(); } final List<Integer> res = reverse(list, index + 1); res.add(list.get(index)); return res; } 而不是直接reverse(list, 0)


最后一点,正如@Sundeep指出的那样,在这种情况下,使用一个简单的循环会更有效 - 但我们相信你真的想要玩递归......:)

答案 1 :(得分:0)

您要添加到已包含5个元素的列表中。如果您不想要原始元素,则应添加到新列表中。

答案 2 :(得分:0)

似乎对基本要求存在误解。

考虑一下:你想要删除列表中除最后一个元素之外的所有元素。改变列表(或子列表)是一个坏主意,因为导致的状态不是由自然递归定义的。

那就是说,让我们扔掉一些东西:

  • 将传入的List视为final - 也就是说您无法重新分配或安全地修改它。

  • 在你递归时耗尽清单。每个切片应比其上方的切片少一个。返回仅包含该切片的List

  • 也不关心列表的大小。递归应该能够像调用堆栈允许的那样工作。

那说......考虑一下:

private static <Type> List<Type> listToReverse(int index, final List<Type> list) {
    final List<Type> reversedList = new ArrayList<>();
    if(index == list.size()) {
        return reversedList;
    } else {
        reversedList.addAll(listToReverse(index++, list.subList(index, list.size())));
        reversedList.add(list.get(index - 1));
    }
    return reversedList;
}

我故意将这个通用化,并将公开调用作为练习留给读者。

请记住基本情况 - 如果我正在阅读的当前“索引”位置等于列表本身的大小,我无所事事,所以我可以安全地返回空列表。然后,我逐渐开始将索引0中的元素添加到size - 1

E.g。如果我使用索引起始位置为0进行此递归调用,那么当我达到列表大小时,我将size - 1中的元素添加到列表中。