如何使用递归返回单链表中的第n个最后一个元素

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

本文关键字:元素 最后一个 链表 递归 何使用 返回 单链表      更新时间:2023-10-16

所以我有这个递归解决方案来打印列表末尾的第n个元素:

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;
}

但是我不知道如何使用递归来返回那个元素。有可能吗?

尝试次数:

  • 如果我有一个静态Node*,当(++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;
    }
    
  • 也可以将引用传递给out节点,并将第n个元素分配给它

但是有更好的方法吗?这些静态在我看来不太干净。

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;
}

以下是我的操作方法(我希望advance的作用从上下文中显而易见):

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);
}

如果要将默认参数隐藏在调用程序之外,请使用helper函数。无论如何,它只是为了提高效率,如果你想要非常慢的代码,那么就不用它,在每个递归步骤调用advance

您几乎不应该仅仅为了使递归工作而需要static变量。您总是可以添加具有默认值的参数,或者编写具有额外参数的辅助函数并调用它来完成所有工作。除了它们可能给读取器带来的任何混乱之外,它们还使函数成为非线程安全的,并且不能从信号处理程序中重新进入。

我的代码执行2 * len - n节点前进,而您的代码只执行len(加上递归返回的n工作)。如果你想坚持你的性能特征,但牺牲尾部递归,那么像这样的东西(我要么在这方面落后一个,要么在我的第一个答案上落后,这取决于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);
}

就我个人而言,我会使用从前面开始的第n个函数倒数到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);
}

并计算列表中元素的数量(如果需要,可以递归)

int get_list_length(Node* node) {
    if (!node)  {
        return 0;            
    }
    return 1 + get_list_length(node->next);
}

因此,我可以将索引计算为第一个索引的第n个

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);
}

在这里,我相信我有一种在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);
}

这是负责将last指针移动到nth位置的主要尾部递归块,并且一旦到达位置,就移动node&last指针在一起。

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

这是为了保持美观而调用的函数。