繁体   English   中英

递归地反转单链接,基于哨兵的列表(有效,但不是我想要的方式)

[英]Reversing a singly linked, sentinel based, list recursively (works, but not in the way I'd like it to)

我正在准备面试,并编写了此简单功能以递归地反转单个链接列表。 第一个节点是前哨节点head 以下代码适用于: list.reverse(list.head.next) ,但是如果我只是将其传递给head则似乎无法使其正常工作。

public Node<T> reverse(Node<T> current)
{
    if (current == null)
        return head;

    if (current.next == null)
    {
        head.next = current;
        return current;
    }

    reverse(current.next).next = current;
    current.next = null;
    return current;
}

我认为当我将其传递给head而不是head.next时它head.next因为我说current.next = null ,但是即使我检查current == head还是current.data == null且仅使用current.next = null如果这些都不是,则仍然无效。 我敢肯定有一个非常简单的修复程序,但是我现在还没有看到。

上面的如果通过的head将返回一个空列表,并且如果进行了建议的更改,只是无法完成运行,但是我没有得到任何错误。

(编辑)我现在可以解决您的问题:

简单来说,前哨头只是充当指向第一个节点的指针,而不是链表的一部分。 因此,它不会参与反向过程,并且需要单独处理。

这意味着原始列表如下所示:

HEAD -> a -> b -> c -> null

反向后,它看起来应该像

HEAD -> c -> b -> a -> null

简而言之,它看起来应该像(假设传入head.next时您的代码已经可以使用)

public Node<T> reverse(Node<T> current)
{
    if (current == head) {
        return reverse(current.next);
    }

    // rest of your original code.
}

只是进一步建议:

作为列表类的公共实例方法,您的reverse()方法不应接受当前节点,因为从概念上讲,它对于调用者而言毫无意义。

我相信您应该对此方法进行保护,这意味着:

public void reverse() {
    this.head = reverseInternal(head);
}

private Node<T> reverseInternal(Node<T> node) {
    // your original reverse logic
}

有了这种封装,当您传递哨兵头时,您甚至无需reverseInternal(head.next)去使逆向工作:您可以在公共的reverse()方法中简单地调用reverseInternal(head.next)

第一:如果返回空列表,则“不起作用”。

头不必为空节点。 通常,您应该仅将第一个节点(在您的情况下为list.head.nextlist.head.nextlist.head head应该是列表开始的引用,而不是单独的节点。

当您将代码传递给list.head时,您的代码清空列表的原因是它将list.head.next设置为null。 这是因为您假定传递到列表的节点是常规节点,而头节点是特殊节点。

这是您的假设的解决方案(我假设有人坚持使用这种奇怪的超脱头法。如果您自己设计列表,请不要这样做。请...)

public Node<T> reverse(Node<T> current)
{
    if (current == null)
        return head;

    if (current.next == null)
    {
        head.next = current;
        return current;
    }
    Node<T> temp = current.next;
    current.next = null;
    head.next = temp;
    reverse(temp).next = current;
    return current;
}

说明:这仍然将最后一个节点的下一个设置为null ,但是在列表中遍历列表时,将列表的头部向下推了一个点,最终将其指向最后一个(现在是第一个)成员。

这有点功课。

但是还是。

一般来说:

f(Node<T> current, ...) {

     f(current.next, ...);

}

对于列表a > b > c > d > e端坐在midle d ,一个可能已经建成c > b > a不已,所以你猜怎样,需要作为附加参数f

祝好运。


评论后:

public Node<T> reverse(Node<T> current)
{
    return reverseRec(current, null);
}

/**
 * @param current to-do (sub-)list.
 * @param resultDone done reversed list sofar.
 * @return reversed result.
 */
public Node<T> reverseRecursively(Node<T> current, Node<T> resultDone)
{
    if (current == null) {
        return resultDone;
    }
    Node<T> next = current.next;
    current.next = resultDone;
    return reverseRecursively(next, current);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM