简体   繁体   中英

How to return the nth last element in a singly linked list using recursion?

So I have this recursive solution to print the nth element from the end of the list:

void print_nth_from_last_rec(Node* node, int n) {

    static int count { 0 };

    if (!node) return;

    print_nth_from_last_rec(node->next, n);

    if (++count == n)
        cout << node->data;

}

But I can't figure out how to return that element using recursion. Is it possible?

Attempts:

  • I can do it if I have a static Node* that will be assigned to when (++count == n) :

     Node* get_nth_from_last_rec(Node* node, int n) { static int count { 0 }; static Node* ret{ nullptr }; if (node) { get_nth_from_last_rec(node->next, n); if (++count == n) ret = node; } return ret; } 
  • It is also possible to pass in a reference to the out Node and assign the nth element to it.

But is there a better way? These statics don't look very clean to me.

Node* get_nth_from_last_rec(Node* node, int& n)
{
    if (node)
    {
        Node* result = get_nth_from_last_rec(node->next, n);
        if (result)
            return result;
        else if (! n--)
            return node;
    }
    return nullptr;
}

Here's how I'd do it (I hope it's obvious from context what advance does):

Node* get_nth_from_last(Node* node, int n, Node *ahead = 0) {
    if (ahead == 0) {
        // might like to check for size < n at the same time
        // and return something to indicate error in that case
        ahead = advance(node, n);
    }
    if (ahead->next == 0) return node; // or whatever the end condition is
    return get_nth_from_last(node->next, n, ahead->next);
}

If you want to hide that default parameter away from the caller, then use a helper function. It's only needed for efficiency anyway, if you want really slow code then do without it and call advance at every recursive step.

You should pretty much never need static variables just to make your recursion work. You can always add parameters with default values, or else write a helper function with extra parameters and call that to do all the work. Aside from any confusion they might cause the reader, they make the function non-thread-safe, and non-reentrant from signal handlers.

My code does 2 * len - n node advances, and yours only does len (plus n pieces of work coming back out of the recursion). If you want to stick with your performance characteristics but sacrifice tail recursion, then something like this (I'm either out-by-one on this, or on my first answer, depending on the meaning of n ...):

Node* get_nth_from_last_helper(Node* node, int &depth) {
    if (node == 0) return 0;
    Node *n = get_nth_from_last_helper(node->next, depth);
    --depth;
    return (depth == 0) ? node : n;
}

Node *get_nth_from_last(Node *node, int n) {
    return get_nth_from_last_helper(Node *node, n);
}

Personally I would use the nth from front function count down to 0

Node* get_nth_from_first_rec(Node* node, int n) {
    if (!node || n == 0) {
        return node;
    }

    return get_nth_from_last_rec(node->next, n - 1);
}

And count the number of elements in the list (recursively if you want)

int get_list_length(Node* node) {
    if (!node)  {
        return 0;            
    }

    return 1 + get_list_length(node->next);
}

So then I could compute the index as an nth from first index

Node* get_nth_from_last_rec(Node* node, int n) {
    int count = get_list_length(node);
    return get_nth_from_first_rec(node, n - count);
}

Here I believe I have a neat tail recursion way of solving it in Java.

public static LinkedListNode findnthToLastRecursionHelper(LinkedListNode node, LinkedListNode last,int pos){
    if(node==null) return null;
    if(pos<1)
    {
        pos=1; //We have reached the nth iteration for last, now time to increment node and last together.
        node = node.next;
        if(last==null) return node;
    }
    else if(last==null) return null;
    return findnthToLastRecursionHelper(node,last.next,--pos);
}

This is the main tail recursion chunk that cares of moving the last pointer to the nth position, and once position is reached it moves node & last pointer together.

public static LinkedListNode findnthToLastRecursion(LinkedListNode head,int pos){         
    return findnthToLastRecursionHelper(head,head.next,pos);
}

This is the caller function in order to maintain the aesthetics.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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