如何在给定头节点的情况下递归地找到链表中最大的项?
int findLargest (ListNode *p)
// --------------------------------------------------------------------------
// Preconditions: list head pointer is passed as a parameter.
// Postconditions: returns the largest value in the linked list.
// --------------------------------------------------------------------------
{
if (p->item != NULL)
{
int largest = p->item;
if (largest > p->next->item)
...
}
...
}
是否可以编写仅传递指针作为参数的递归函数?我不知道如何在不添加更多参数的情况下做到这一点。有什么想法吗?我只使用顺序搜索。没什么花哨的。
这是类 List 中需要的部分:
struct ListNode
{
ListItemType item; // A data item on the list.
ListNode *next; // Pointer to next node
}; // end ListNode
ListNode *head; // Pointer to linked list of items.
我主要担心问题的可行性。仅用指针作为参数可以完成此操作吗?
int findLargest (ListNode *p)
// --------------------------------------------------------------------------
// Preconditions: list head pointer is passed as a parameter.
// Postconditions: returns the largest value in the linked list.
// --------------------------------------------------------------------------
{
if (p->item != NULL)
{
int largest = p->item;
if (largest > p->next->item)
...
}
...
}
Is it possible to write this recursive function passing only a pointer as a parameter? I can't figure out how to do this without adding more parameters. Any ideas? I am only using sequential search. Nothing fancy.
Here is the portion of class List that will be needed:
struct ListNode
{
ListItemType item; // A data item on the list.
ListNode *next; // Pointer to next node
}; // end ListNode
ListNode *head; // Pointer to linked list of items.
I am mainly worried about the feasibility of the problem. Can this be done with only a pointer as a parameter?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
虽然 C 不需要尾递归优化,但如果您可以将其转换为尾递归(并且您不需要在这里做很多工作),那么,当应用该优化时,您可以保持可读性、清晰度和递归的简洁性与最佳非递归解决方案具有相同的性能(时间和空间)。
我稍微修改了函数的条件,以便它可以在没有节点的空列表上工作(其中 p 为 null),并且在这种情况下将返回 null。这是尾递归,并且确实需要另一个参数:
请注意,您使用主条目 findLargest 来设置实际递归 findLargestRecurse 的初始条件/上下文。
但是,我会将尾递归编写为迭代 while 循环,以减少对当前编译器特定且在 C 中通常不熟悉的内容的依赖,这并不难做到:
您可以分离出
!largest< /code> 通过预先执行此操作来从循环中获得条件,通过检查基本情况,就像第一个 findLargest 所做的那样(“标记 A”)。
现在看看这个,你可能想知道为什么我称递归版本更简洁:它确实不适合这个简单的例子。这部分是因为 C 的设计有利于迭代(特别注意 for 循环),部分是因为我试图在递归中变得冗长,而不是像通常那样将其压缩(这样你可以更容易地理解它),剩下的就是因为这只是一个简单的问题。
Though tail-recursion optimization isn't required by C, if you can transform it into tail-recursion (and you can without a lot of work here), then, when that optimization is applied, you can maintain the readability, clarity, and conciseness of recursion with the same performance (time and space) as the best non-recursive solution.
I've slightly modified the function's conditions so it can work on an empty list with no nodes (where p is null) and will return null in that case. This is tail-recursive, and does require another parameter:
Notice you use the main entry, findLargest, to setup the initial conditions/context for the actual recursion, findLargestRecurse.
However, I'd write that tail-recursion as an iterative while loop to rely less on what's currently both very compiler-specific and generally unfamiliar in C, which is not hard to do:
You can separate out the
!largest
condition from the loop by doing it beforehand, by checking a base case just like the first findLargest does ("mark A").And looking at this now, you may wonder why I called the recursive version more concise: it really isn't for this trivial example. That's partially because C is designed to favor iteration (notice the for loop in particular), somewhat because I tried to be verbose in the recursion instead of squashing it down as I would normally (so you could understand it easier), and the rest is because this is just a simple problem.
我发现大多数递归问题都可以使用思考框架/模板来解决:
在这种情况下,答案是
玩得开心。 :)
I find that most recursive problems can be solved using the framework/template of thinking about:
In this case, the answers are
Have fun. :)
我已经看到一些发布的代码,并且忍不住添加我自己的......因为我真的认为它可以更简单地完成:)
我认为
item
是数字类型。正如您所看到的,简单得多,而且我冒昧地添加了一个
const
因为我们当然不需要修改列表本身!I have seen some code posted and could not refrain to add my own... because I really think it could be done more simply :)
I suppose that
item
is of a numeric type.As you can see, much simpler, and I took the liberty to add a
const
since we're certainly not going to have to modify the list itself!这绝对是可行的,尽管我同意递归不是解决这个问题的最佳方案。在这种情况下,非递归代码将更容易阅读(递归),更快(函数调用的开销),并且内存效率更高(显然有更多的堆栈帧)。
每个递归调用都返回其值或列表其余部分的值中的较大者。
当
next
项为空时,递归停止。This is definitely feasible, although I agree that recursion is not the best solution to solve this problem. In this case, non-recursive code would be easier to read (recursion), faster (overhead of function call), and more memory efficient (obviously more stack frames).
Each recursive call returns the greater of either it's value or the value from the rest of the list.
Recursion stops when the
next
item is null.Java版本
Java Version
如果您只想返回最大值,那么您几乎已经写好了。
如果您希望返回指向最大节点的指针,则参数需要是双指针(**),或者函数需要返回指针。
实际上没有理由递归地执行此操作。我认为这只是学习递归的练习,但我觉得这是一个糟糕的学习示例。
If you are looking to return just the largest value, then yes you pretty much already have it written.
If you are looking to return a pointer to the largest node, then the parameter needs to be a double pointer (**), or the function needs to return a pointer.
Really there is no reason to do this recursively. I assume this is just an exercise to learn about recursion, but I feel it is a poor learning example.
这是另一个惯用的递归解决方案,类似于 Matthieu 的解决方案。与他的解决方案不同,这个解决方案需要一个空列表 - 可以说,获取空列表中的最小项目并不是一个有意义的操作:
这个解决方案读起来很像数学定义,使用“cases”符号:
Here’s another idiomatic recursive solution, similar to Matthieu’s. Unlike his solution, this one requires an empty list – arguably, taking the smallest item of an empty list isn’t a meaningful operation:
This one reads much like a mathematical definition, using the “cases” notation:
不需要递归,并且您的示例不是递归(它必须调用自身)。
仅使用指针作为参数就可以做到这一点。
提示:将 p 分配给 p->next 以在列表中前进。
No need for recursion, and your example isn't recursion (it would have to call itself).
It is possible to do this with only a pointer as a parameter.
Hint: Assign p to p->next to advance through the list.
始终将递归问题分为两个步骤:停止条件和“问题的其余部分”。首先考虑停止条件。在链表中,它通常是空节点。但就您的情况而言,请考虑当给定节点为空时会发生什么。你会返回什么?事实是,无论如何你都必须返回最大值,并且当列表中没有元素时,就没有 max 元素。在这种情况下,也许您可以假设列表必须至少有一个元素。
那么停止条件是什么呢?停止条件是当列表中有单个元素时;在这种情况下,最大值是该节点的值。
下一步是递归步骤。假设您有一个链接到列表的元素。请注意我如何描述链表:链接到链表的节点。如果该节点的最大值大于列表的最大值,则最大值为该节点的值,否则为列表的最大值。
Always break recursion problems into two steps: the stop condition and "the rest of the problem". Start by thinking about the stop condition. In linked lists it's usually the null node. But in your case, think what happens when the given node is null. What would you return? The truth is that you have to return the max value no matter what, and when there are no elements in the list there is no max element. In this case maybe you can just assume that a list must therefore have at least one element.
So what's the stop condition? The stop condition is when there's a single element in the list; and in this case the max value is that node's value.
The next step is the recursive step. Suppose you have an element linked to a list. And pay attention how I describe a linked list: a node linked to a linked list. The max value is the value of that node if it's larger than the largest value of the list, or the largest value of the list otherwise.