Traverse from end to front ( C++ LL Q:1 ) - c++

int LinkedList::DoStuff()
{
Node *Current = next_;
while ( Current != NULL )
{
Current = Current->next_;
length_++;
}
// At the last iteration we have reached the end/tail/last node
return length_;
}
there are no more nodes beyond the last. How can i traverse to the tail-end to the front-head?

Unless your linked list is a doubly-linked one, this is difficult to do. Recursion is one way, assuming you don't have lists so big that you'll run out of stack space, something like this (pseudo-code):
DoStuffBackwards (currNode) {
if (currNode != NULL) {
DoStuffBackwards (currNode->next);
// Process currNode here.
}
}
DoStuffBackwards (firstNode);
This works because you keep calling DoStuffBackwards() for the next node until you exhaust the list then, as you roll back up the recursion stack, you process each node.

If you just want to go backwards from last node to current node, than Pax's answer (using recursion) is your best bet, also see my version below. If your current node is not the head of your non-circular-singly-linked-list, and you want to go from current node to head node, it is impossible.
int LinkedList::DoStuff()
{
return DoStuffBackward(next_, 0);
}
int LinkedList::DoStuffBackward(Node* node, int n)
{
if (!node)
{
return n;
}
int len = DoStuffBackward(node->next_, n + 1);
std::cout << "doing stuff for node " << n << std::endl;
return len;
}

This has the smell of homework, so no code, but here's an overview of a solution that doesn't require recursion:
If you want to run through the list backward one option to relink the list to point backwards as you're traversing it to find the end. Then as you re-traverse the list (which visits the nodes in the reverse order from the original list) you repeat the relinking same as before and the list ends up in its original order.
This is simple in concept, but handling the pointers and links correctly (especially at the start and end of the list) can be a bit tricky.

Recursion can work, as can building an auxiliary data structure, such as an array with one entry for each element of the original list. If you want a solution for a single-threaded list without requiring O(n) extra storage, the best bet is to reverse the list in place as Michael suggests. I wrote an example for this, [but I'll leave it out given the concern about homework]. One caution about reversing the list: if there are any other data structures that hold pointers to the original list, and you might be accessing them during your traversal, they won't work if they need to access the list while it's reversed, and this might lead to data corruption if they try to modify the list.
Update: Ok, here's the (C++) routine to reverse a list in place. It hasn't been tested, though. And I'll note that if this is homework, the poster still needs to figure out how to use this routine correctly to get a complete answer.
Node *ReverseList(Node *head) {
// Reverse a single-threaded list in place, return new head
Node *prev=NULL;
Node *cur=head;
while (Node *next=cur->next_) {
cur->next_ = prev;
prev = cur;
cur = next;
}
cur->next_ = prev;
return cur;
}

push the list on a stack and then pop them off.

Is your linked list class doubly-linked or singly-linked? If there is no previous pointer inside each node, you can't traverse backwards.
I also suggest you post more code and take the time to make your question readable.

Related

Node search in Binary Tree overflows stack

I use the following method to traverse* a binary tree of 300 000 levels:
Node* find(int v){
if(value==v)
return this;
else if(right && value<v)
return right->find(v);
else if(left && value>v)
return left->find(v);
}
However I get a segmentation fault due to stack overflow.
Any ideas on how to traverse the deep tree without the overhead of recursive function calls?
*
By "traverse" I mean "search for a node with given value", not full tree traversal.
Yes! For a 300 000 level tree avoid recursion. Traverse your tree and find the value iteratively using a loop.
Binary Search Tree representation
25 // Level 1
20 36 // Level 2
10 22 30 40 // Level 3
.. .. .. .. .. .. ..
.. .. .. .. .. .. .. .. // Level n
Just to clarify the problem further. Your tree has a depth of n = 300.000 levels. Thus, in the worst case scenario a Binary Search Tree (BST) will have to visit ALL of the tree's nodes. This is bad news because that worst case has an algorithmic O(n) time complexity. Such a tree can have:
2ˆ300.000 nodes = 9.9701e+90308 nodes (approximately).
9.9701e+90308 nodes is an exponentially massive number of nodes to visit. With these numbers it becomes so clear why the call stack overflows.
Solution (iterative way):
I'm assuming your Node class/struct declaration is a classic standard integer BST one. Then you could adapt it and it will work:
struct Node {
int data;
Node* right;
Node* left;
};
Node* find(int v) {
Node* temp = root; // temp Node* value copy to not mess up tree structure by changing the root
while (temp != nullptr) {
if (temp->data == v) {
return temp;
}
if (v > temp->data) {
temp = temp->right;
}
else {
temp = temp->left;
}
}
return nullptr;
}
Taking this iterative approach avoids recursion, hence saving you the hassle of having to recursively find the value in a tree so large with your program call stack.
A simple loop where you have a variable of type Node* which you set to the next node, then loop again ...
Don't forget the case that the value you are searching for does not exist!
You could implement the recursion by not using the call stack but a user-defined stack or something similar; this could be done via the existing stack template. The approach would be to have a while loop which iterates until the stack is empty; as the existing implementaion uses depth-first search, elimination of the recursive calls can be found here.
When the tree that you have is a Binary Search Tree, and all you want to do is search for a node in it that has a specific value, then things are simple: no recursion is necessary, you can do it using a simple loop as others have pointed out.
In the more general case of having a tree which is not necessarily a Binary Search Tree, and wanting to perform a full traversal of it, the simplest way is using recursion, but as you already understand, if the tree is very deep, then recursion will not work.
So, in order to avoid recursion, you have to implement a stack on the C++ heap. You need to declare a new StackElement class that will contain one member for each local variable that your original recursive function had, and one member for each parameter that your original recursive function accepted. (You might be able to get away with fewer member variables, you can worry about that after you have gotten your code to work.)
You can store instances of StackElement in a stack collection, or you can simply have each one of them contain a pointer to its parent, thus fully implementing the stack by yourself.
So, instead of your function recursively calling itself, it will simply consist of a loop. Your function enters the loop with the current StackElement being initialized with information about the root node of your tree. Its parent pointer will be null, which is another way of saying that the stack will be empty.
In every place where the recursive version of your function was calling itself, your new function will be allocating a new instance of StackElement, initializing it, and repeating the loop using this new instance as the current element.
In every place where the recursive version of your function was returning, your new function will be releasing the current StackElement, popping the one that was sitting on the top of the stack, making it the new current element, and repeating the loop.
When you find the node you were looking for, you simply break from the loop.
Alternatively, if the node of your existing tree supports a) a link to its "parent" node and b) user data (where you can store a "visited" flag) then you don't need to implement your own stack, you can just traverse the tree in-place: in each iteration of your loop you first check if the current node is the node you were looking for; if not, then you enumerate through children until you find one which has not been visited yet, and then you visit it; when you reach a leaf, or a node whose children have all been visited, then you back-track by following the link to the parent. Also, if you have the freedom to destroy the tree as you are traversing it, then you do not even need the concept of "user data": once you are done with a child node, you free it and make it null.
Well, it can be made tail recursive at the cost of a single additional local variable and a few comparisons:
Node* find(int v){
if(value==v)
return this;
else if(!right && value<v)
return NULL;
else if(!left && value>v)
return NULL;
else {
Node *tmp = NULL;
if(value<v)
tmp = right;
else if(value>v)
tmp = left;
return tmp->find(v);
}
}
Walking through a binary tree is a recursive process, where you'll keep walking until you find that the node you're at currently points nowhere.
It is that you need an appropriate base condition. Something which looks like:
if (treeNode == NULL)
return NULL;
In general, traversing a tree is accomplished this way (in C):
void traverse(treeNode *pTree){
if (pTree==0)
return;
printf("%d\n",pTree->nodeData);
traverse(pTree->leftChild);
traverse(pTree->rightChild);
}

Insertion Sort to Sort Nodes in a LinkedList

Im trying to use the insertion sort method in order to sort nodes from a LinkedList. I've adjusted the code so many times but I can't quite seem to get it, keep getting different types of results none which are sorted.
Heres the code:
Node* sort_list(Node* head)
{
Node* node_ptr = NULL;
for(Node* i = head->next; i->next != NULL; i = i->next){
if (i->key < head->key) {
node_ptr = i;
head = head->next;
}
}
return node_ptr;
}
This is a homework problem so instead of outright writing a code, I will first point out where you went wrong.
In an insertion sort like algorithm, obviously there needs to be some kind of swapping that needs to be done between elements that are out of place (that is need to be inserted). Hence start with thinking about how you can swap two elements of the array. Pay special attention to the cases when one is head or one is tail.
Your implemented code doesn't have any trace of pointer swaps so this is where you are wrong.
Next you must think about the cases when we need to sort. In this case, it is rather simple. If the current element and the next are in sorted order (assuming ascending order, current < next). Then nothing needs to be done but simply make the next one the current.
Then you can obviously infer that violation of this case is when you need to swap the elements. After the swap (with proper attention to where the pointers were and will be after sorting), repeat the process till you hit the null wall.
P.S : This is a possible duplicate of another SO question.

Non iterative equivalent for reversing a linked list

I am reading about list traversals in Algorithms book by RobertSedwick. Function definitions are shown below. It is mentioned that it is possible to have traverse and remove functions can have iterative counter parts, but traverseR cannot have. My question why traverseR cannot have iterative counter part? Is it that if recursive call is not end of function i.e., like in traverse then we cannot have iterative, Is my understanding right?
Thanks for your time and help.
void traverse(link h, void visit(link))
{
if (h == 0) return;
visit(h);
traverse(h->next, visit);
}
void traverseR(link h, void visit(link))
{
if (h == 0) return;
traverseR(h->next, visit);
visit(h);
}
void remove(link& x, Item v)
{
while (x != 0 && x->item == v)
{ link t = x; x = x->next; delete t; }
if (x != 0) remove(x->next, v);
}
traverseR uses the call stack to store pointers to all the nodes of the list, so that they can be accessed in reverse order as the call stack unwinds.
In order to do this without a call stack (i.e. non-recursively), you'll need some other stack-like data structure to store these pointers in.
The other functions simply work on the current node and move on, with no need to store anything for use after the recursive function call returns. This means that the tail recursion can be replaced with a loop (either by modifying the code or, depending on the compiler, letting it determine that that's possible and make the transformation itself).
Assuming that the list is single-linked, it is not possible to visit it iteratively in the backward order because there's no pointer from a node to a previous node.
What the recursive implementation of traverseR essentially does is that it implicitly reverses the list and visits it in the forward order.
You could write and iterative version of traverseR using a stack: in a loop iterate from one node to another, pushing the nodes on the stack. When you get to the end of the list then, in another loop, pop and visit the nodes you visited.
But his is basically what the recursive version does.
It is possible to traverse a singly linked list in reverse order with only O(1) extra space -- i.e., without a stack of previously visited nodes. It is, however, a little tricky, and not at all thread safe.
The trick to this is to traverse the list from beginning to end, reversing it in place as you do so, then traverse it back to the beginning, reversing it again on the way back through.
Since it is a linked list, reversing it in place is fairly straightforward: as you get to a node, save the current value of its next pointer, and overwrite that with the address of the previous node in the list (see the code for more detail):
void traverseR(node *list, void (*visit)(node *)) {
node *prev = nullptr;
node *curr = list;
node *next;
if (!curr)
return;
// Traverse forwards, reversing list in-place as we go.
do {
next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
} while (curr->next);
// fix up so we have a fully reversed list
curr->next = prev;
prev = nullptr;
// Traverse the reversed list, visiting each node and reversing again
do {
visit(curr);
next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
} while (curr->next);
}
Like almost anything dealing with linked lists, I feel obliged to add that (at least IMO) they should almost always be treated as a purely intellectual exercise. Using them in real code is usually a net loss. You typically end up with code that's slow, fragile, and hard to understand, as well as typically wasting quite a bit of memory (unless the data you store in each node is pretty big, the pointer can often use as much space as the data itself).
My question why traverseR cannot have iterative counter part? Is it that if recursive call is not end of function i.e., like in traverse then we cannot have iterative, Is my understanding right?
Correct. The functions traverse and remove end with a call to themselves. They are tail recursive functions. The call in traverseR to itself is not at the end of the function; traverseR is not tail recursive.
Recursion in general has an expense of creating and later destroying stack frames. This expense can be completely avoided with tail recursive functions by changing the recursion into iteration. Most compilers recognize tail recursive functions and convert the recursion to iteration.
It is possible to write an iterative version of traverseR depending on what you mean by iterative. If you are limited so a single traversal through the list, it is not possible. But if you can sacrifice a lot processing time it can be done. It does use less memory in the classic speed vs. memory trade-off.
void traverseRI(link h, void visit(link))
{
if (h == 0) return;
link last = 0;
while (last != h)
{
link test = h;
while (test->next != last)
{
test = test->next;
}
visit(test);
last = test;
}
}

Cyclical Linked List Algorithm

I have been asked recently in a job interview to develop an algorithm that can determine whether a linked list is cyclical. As it's a linked list, we don't know its size. It's a doubly-linked list with each node having 'next' and 'previous' pointers. A node can be connected to any other node or it can be connected to itself.
The only solution that I came up at that time was to pick a node and check it with all the nodes of the linked list. The interviewer obviously didn't like the idea as it is not an optimal solution. What would be a better approach?
What you are looking for is a cycle-finding algorithm. The algorithm Joel refers to is called either the 'tortoise and hare' algorithm or Floyd's cycle finding algorithm. I prefer the second because it sounds like it would make a good D&D spell.
Wikpedia overview of cycle finding algorithms, with sample code
The general solution is to have 2 pointers moving at different rates. They will eventually be equal if some portion of the list is circular. Something along the lines of this:
function boolean hasLoop(Node startNode){
Node slowNode = startNode;
Node fastNode1 = startNode;
Node fastNode2 = startNode;
while (slowNode && fastNode1 = fastNode2.next() && fastNode2 = fastNode1.next()){
if (slowNode == fastNode1 || slowNode == fastNode2)
return true;
slowNode = slowNode.next();
}
return false;
}
Blatantly stolen from here: http://ostermiller.org/find_loop_singly_linked_list.html
Keep a hash of pointer values. Every time you visit a node, hash its pointer and store it. If you ever visit one that already has been stored you know that your list is circular.
This is an O(n) algorithm if your hash table is constant.
Another option is that since the list is doubly linked, you can traverse the list and check if the next pointers previous is always the current node or null and not the head. The idea here is that a loop must either encompass the entire list or look something like this:
- -*- \
\ \
\---
At Node * there are 2 incoming links only one of which can be the previous.
Something like:
bool hasCycle(Node head){
if( head->next == head ) return true;
Node current = head -> next;
while( current != null && current->next != null ) {
if( current == head || current->next->prev != current )
return true;
current = current->next;
}
return false; // since I've reached the end there can't be a cycle.
}
You can handle a general complete circular list like this: Loop through the linked list via the first element until you reach the end of the list or until you get back to the first element.
But if you want to handle the case where a portion of the list is circular then you need to also move ahead your first pointer periodically.
Start with two pointers pointing at the same element. Walk one pointer through the list, following the next pointers. The other walks the list following the previous pointers. If the two pointers meet, then the list is circular. If you find an element with a previous or next pointer set to NULL, then you know the list is not circular.
[Edit the question and subject has been reworded to clarify that we're checking for cycles in a doubly linked list, not checking if a doubly linked list is merely circular, so parts of this post may be irrelevant.]
Its a doubly link list with each node
having 'next' and 'previous' pointers.
Doubly-linked lists are commonly implemented with the head and tail of the list pointing to NULL to indicate where they end.
[Edit] As pointed out, this only checks if the list is circular as a whole, not if it has cycles in it, but that was the wording of the original question.
If the list is circular, tail->next == head and/or head->prev == tail. If you don't have access to both the tail and head node and only have one of those but not both, then it should suffice to simply check if head->prev != NULL or tail->next != NULL.
If this isn't a sufficient answer because we're only given some random node [and looking for cycles anywhere in the list], then all you have to do is take this random node and keep traversing the list until you reach a node that matches (in which case it is circular) or a null pointer (in which case it's not).
However, this is essentially the same thing as the answer you already provided which the interviewer didn't like. I'm quite certain that without some magical hack, there is no way to detect a cycle in a linked list, provided a random node, without a linear complexity algorithm.
[Edit] My mind has switched gears now with the focus on detecting cycles in a list as opposed to determining if a linked list is circular.
If we have a case like:
1<->2<->3<->[2]
The only way I can see that we can detect cycles is to keep track of all the elements we traversed so far and look for any match along the way.
Of course this could be cheap. If we're allowed to modify the list nodes, we could keep a simply traversed flag with each node that we set as we're doing this. If we encounter a node with this flag already set, then we've found a cycle. However, this wouldn't work well for parallelism.
There is a solution proposed here [which I stole from another answer] called "Floyd's Cycle-Finding Algorithm". Let's take a look at it (modified to make it a little easier for me to read).
function boolean hasLoop(Node startNode)
{
Node fastNode2 = startNode;
Node fastNode1 = startNode;
Node slowNode = startNode;
while ( slowNode && (fastNode1 = fastNode2.next()) && (fastNode2 = fastNode1.next()) )
{
if (slowNode == fastNode1 || slowNode == fastNode2)
return true;
slowNode = slowNode.next();
}
return false;
}
It basically involves using 3 iterators instead of 1. We can look at a case like: 1->2->3->4->5->6->[2] case:
First we start at [1] with a fast iterator to [2] and another at [3] or [1, 2, 3]. We stop when the first iterator matches either of the two second iterators.
We proceed with [2, 4, 5] (the first fast iterator traverses the next node of the second fast iterator, and the second fast iterator traverses the next node of the first fast iterator after that). Then [3, 6, 2], and finally [4, 3, 4].
Yay, we've found a match, and have thus determined the list to contain a cycle in 4 iterations.
Assuming that someone says "Here a pointer to a member of a list. Is it a member of a circular list?" then you could examine all reachable members in one direction of the list for pointers to the one node that you were given a pointer to in their pointer which should point away from you. If you decide to go in the next direction then you look for next pointers that are equal to the pointer you were first given. If you choose to go in the prev direction then you look for prev pointers that equal the pointer that you were first given. If you reach a NULL pointer in either direction then you have found the end and know that it is not circular.
You could extend this by going in both directions at the same time and seeing if you bump into yourself, but it gets more complicated and it really doesn't save you anything. Even if you implemented this with 2 threads on a multi-core machine you'd be dealing with shared volatile memory comparisons, which would kill performance.
Alternately, if you can mark each node in the list you could try to determine if there was a cycle by looking for your mark while you searched for the end. If you found your mark in a node you would know that you had been there before. If you found an end before you found one of your marks you would know it wasn't circular. This would not work of another thread were trying to do this at the same time, though, because you would get your marks mixed up, but the other implementation wouldn't work if other threads were reordering the list at the same time as the test.
What you need is Floyd's cycle-finding algorithm. You can also think of finding the the intersection point of the cycle as homework.
Here is a clean approach to test if a linked list has cycles in it (if it's cyclical) based on Floyd's algorithm:
int HasCycle(Node* head)
{
Node *p1 = head;
Node *p2 = head;
while (p1 && p2) {
p1 = p1->next;
p2 = p2->next->next;
if (p1 == p2)
return 1;
}
return 0;
}
The idea is to use two pointers, both starting from head, that advance on different speeds. If they meet each other, that's our clue that there is a cycle in our list, if not, the list is cycle-less.
It is unbelievable how wide can complicated solutions spread.
Here's an absolute minimum required for finding whether a linked list is circular:
bool is_circular(node* head)
{
node* p = head;
while (p != nullptr) {
p = p->next;
if (p == head)
return true;
}
return false;
}

How can I find the largest item in a linked list recursively given the head node?

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?
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:
ListNode* findLargestRecurse(ListNode* p, ListNode* largest) {
// this is an implementation detail, and would not be called directly
// requires that largest is not null, but p may be null
if (!p) return largest;
if (p->item > largest->item) largest = p;
return findLargestRecurse(p->next, largest);
}
// preconditions: list head pointer is passed as a parameter, and may be null
// postcondition: returns the node with the largest value, or null
ListNode* findLargest(ListNode* p) {
if (!p) return 0; // mark A, see below
return findLargestRecurse(p->next, p);
}
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:
// preconditions: list head pointer is passed as a parameter, and may be null
// postcondition: returns the node with the largest value, or null
ListNode* findLargest(ListNode* p) {
ListNode* largest = 0;
for (; p; p = p->next) {
if (!largest || p->item > largest->item) {
largest = p;
}
}
return largest;
}
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:
What information do I have at hand right now?
What information will I get if I make a recursive call?
How can I combine those two to make a final result?
(Also, be sure to be clear about the 'base case'.)
In this case, the answers are
the value in the current node
the largest element in the 'suffix' of the list that comes after this node
hmmm, that's for you to figure out
(What should you return for the empty list? Does the homework say?)
Have fun. :)
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.
#include <algorithm> // std::max
#include <limits> // std::numeric_limits
ListItemType findLargest(const ListNode* p)
{
if (p == 0)
return std::numeric_limits<ListItemType>::min();
else
return std::max(p->item, findLargest(p->next));
}
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!
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.
int findLargest (ListNode *p) {
int current = p->item;
int next;
if (p->next == NULL) {
//The value at this node is obviously larger than a non-existent value
return current;
} else {
//Recur to find the highest value from the rest of the LinkedList
next = findLargest(p->next);
}
//Return the highest value between this node and the end of the list
if (current > next) {
return current;
} else {
return next;
}
}
Recursion stops when the next item is null.
Java Version
return max(head, head.value);
int max(Node node, int currentMax)
{
if(node==null)
return currentMax;
if(node.value>currentMax)
return max(node.next, node.value);
else
return max(node.next, currentMax);
}
If you are looking to return just the largest value, then yes you pretty much already have it written.
int FindLargest(ListNode* node){
if (node != NULL){
int downTheListLargest = FindLargest(node->next);
if (downTheListLargest > node->item){
return downTheListLargest;
}
return node->item;
}
return //?? some max negative value
}
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.
ListNode* FindLargest(ListNode* node){
if (node == NULL){
return NULL;
}
ListNode* downTheListLargestNode = FindLargest(node->next);
if (downTheListLargestNode && downTheListLargestNode->item > node->item){
return downTheListLargestNode;
}
return node;
}
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.
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:
// Precondition: list is non-empty.
int find_largest(ListNode const* n) {
assert(n != 0 && "find_largest requires non-empty list.");
return n->next == 0 ? n->item
: max(n->item, find_largest(n->next));
}
This one reads much like a mathematical definition, using the “cases” notation:
{ item(i), if i is the last node
largest(i) = {
{ max{item(i), largest(i+1)} else.
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.
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.