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

时间:2013-12-15 22:29:36

标签: c++ recursion linked-list

所以我有这个递归解决方案打印列表末尾的第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个元素。

但是有更好的方法吗?这些静电对我来说看起来不太干净。

4 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:3)

以下是我如何做到的(我希望从上下文中可以明显看出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);
}

如果要将该默认参数隐藏在远离调用者的位置,请使用辅助函数。它只需要效率,如果你想要真正慢的代码,那么没有它,并在每个递归步骤调用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);
}

答案 2 :(得分:0)

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

答案 3 :(得分:0)

在这里,我相信我有一种用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&amp; last指针在一起。

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

这是调用者的功能,以保持美观。