【问题标题】:Finding the maximum value of a linked list recursively递归查找链表的最大值
【发布时间】:2017-03-29 22:07:30
【问题描述】:

我需要在一个名为 Node 的类中编写一个名为 findMax 的 Java 方法,该类有两个实例变量:int value 和 Node next。该方法不带参数,并且必须返回链表的最大值。在程序的上下文中,该方法将始终由链表的第一个节点调用(递归调用除外)。当我不小心找到一个可行的解决方案时,我正在努力完成该方法:

public int findMax(){
    int max = value;
    if(next == null){
        return max;
    }
    else{
        if(max <= next.findMax()){
           max = next.value;
        }
        else return max;
    }
    return next.findMax();
}

这个方法正确地返回了我测试过的每个链表的最大值。但是,由于我通过尝试随机排列代码找到了这个解决方案,所以我真的不觉得我理解这里发生了什么。谁能向我解释这是如何/为什么起作用的?另外,如果有更高效的解决方案,将如何实现?

【问题讨论】:

  • 您的代码可以工作,但看起来好像是侥幸,这很好,因为您承认这就是您让它工作的方式。当前形式的效率非常低(相对于输入大小增长的指数时间增加)。你不想在这里调用findMax() 两次,每次调用findMax() 都需要遍历整个列表。我将在我的回答中添加一条说明为什么它不好以及如何调整您的解决方案

标签: java recursion methods linked-list nodes


【解决方案1】:

你可以想象一个链表看起来像这样:

val1->val2->val3->null

递归的工作原理是,最终,您传递给函数的输入可以在不进一步递归的情况下进行处理。在您的情况下,如果next 指针为null,则可以处理 node.findMax()。也就是说,大小为 1 的链表的最大值只是值(递归的基本情况),任何其他链表的最大值是该节点的值的最大值或剩余元素的最大值。

ie) 对于值为 val3 的 Node n3n3.findMax() 只返回值

对于任何其他节点nn.findMax() 返回节点值的最大值或n.next.findMax()

在开头的示例中看起来是这样的:

n1.findMax()
  = Max(n1.value, n2.findMax())
  = Max(val1, Max(n2.value, n3.findMax())
  = Max(val1, Max(val2, n3.value)) // Since n3.next == null
  = Max(val1, Max(val2, val3))

这只是整个列表中的最大值

编辑:根据上面的讨论,虽然你说的可能有效,但有一种更简单的编写程序的方法:

int findMax() {
    if (this.next == null) {
        return this.value;
    } else {
        return Math.max(this.value, this.next.findMax());
    }
}

编辑 2:分解您的代码工作的原因(以及为什么不好):

public int findMax(){
    // This variable doesn't serve much purpose
    int max = value;
    if(next == null){
        return max;
    }
    else{
        // This if condition simply prevents us from following
        // the else block below but the stuff inside does nothing.
        if(max <= next.findMax()){
           // max is never used again if you are here.
           max = next.value;
        }
        else return max;
    }
    // We now compute findMax() again, leading to serious inefficiency
    return next.findMax();
}

为什么效率低下?因为在一个节点上对findMax() 的每次调用都会在下一个节点上对findMax() 进行两次后续调用。这些调用中的每一个都会产生另外两个调用,等等。

解决这个问题的方法是像这样存储next.findMax() 的结果:

public int findMax() {
    if (next == null) {
        return value;
    }
    else {
        int maxOfRest = next.findMax();
        if(value <= maxOfRest) {
            return maxOfRest;
        }
        else return value;
    }
}

【讨论】:

  • 如果需要,可以将其缩短为 return (this.next == null ? this.value : Math.max(this.value, this.next.findMax()));
  • 非常感谢!代码分解特别有用。还有一个问题:为什么将标识符命名为“maxOfRest”?
  • 因为这就是它存储的内容,所以您可以通过比较您正在查看的节点的值与列表中其余节点的最大值来找到整个列表的最大值。跨度>
猜你喜欢
  • 2020-06-06
  • 2015-05-03
  • 2021-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多