使用递归计数双链接列表中的偶数元素

问题描述

我有两个函数一个是NumsEven(),另一个是NumsEvenHelper(Node * ptr),我有一个{2,4,5,10}列表,我应该使用递归来计算偶数,这就是我的想法到现在:

template <typename Data_t>
Data_t DLinkedList<Data_t>::NumEven() {
    Node* ptr = _head;
    return NumEvenHelper(ptr);
}
template <typename Data_t>
Data_t DLinkedList<Data_t>::NumEvenHelper(Node* ptr) {
    
    ptr = _head;
    
    if (empty()) return 0;
    
    else if ((ptr->_data % 2 == 0))
        return 1 + NumEvenHelper(ptr->_next);
    
}

解决方法

为了解决此问题,您可以添加两个成员函数:第一个成员函数是public,另一个是私有函数:

public:
    std::size_t countEven() const noexcept;

private:
    std::size_t countEven(Node *node) const noexcept;

双重链接列表的用户将使用第一个成员函数时,实际的递归/计算中将使用第二个成员函数。

std::size_t countEven() const noexcept {
    return countEven(_head);
}

std::size_t countEven(Node *node) const noexcept {
    if (nullptr != node) {
        if (curr->_data % 2 == 0) {
            return countEven(node->next) + 1;  // since _data is even,increment by one
        } else {
            return countEven(node->next);  // since _data is not even,don't increment
        }
    } else {
        return 0; // in case we reach the end of list,we need to return starting value for counting
    }
}

当然,蕴涵的是_data成员是整数。

,

您实际上有两个 问题...这两个问题都可以通过简单的调试轻松发现。

第一个问题是您没有理由处理列表中的 odd 数据值。

如果ptr->_data为奇数,则NumEvenHelper函数将在不返回任何内容的情况下结束。这将导致未定义的行为,因为您的程序假定该函数将返回有效值。

该函数还将停止对奇数值的递归,因此即使您在列表中的后面有偶数值,也不会被计算在内。

简单的解决方案是简单地添加一个else情况,您只需进行递归调用,而无需添加1

if (empty())
    return 0;
else if ((ptr->_data % 2 == 0))
    return 1 + NumEvenHelper(ptr->_next);
else  // Is odd
    return NumEvenHelper(ptr->_next);

第二个问题是您的助手函数总是设置ptr指向_head,而忽略了传递的参数。

这将导致对非空列表的无限递归,因为递归调用实际上将是:

NumEvenHelper(_head->_next);

您应该在助手功能中具有该分配。


现在需要一点“技巧”(这将使您的代码难以阅读和理解)可以使您不必拥有if,而不必担心else:布尔结果(如比较结果)可以隐式转换为int值,其中1的{​​{1}}和true的{​​{1}}。 / p>

这意味着您可以使用布尔条件作为部分或算术计算来代替0false

例如:

1

如果该值是偶数,则将0添加到递归调用的结果中,否则它将添加if (empty()) return 0; // No else here return (ptr->_data % 2 == 0) + NumEvenHelper(ptr->_next);