正确使用函数指针进行遍历的方法

时间:2019-05-21 05:58:55

标签: c++ binary-search-tree function-pointers traversal inorder

我正在创建一个二进制搜索树模板类,并且想对顺序遍历函数使用函数指针,我对函数指针还可以,但是由于某种原因,一旦代码到位,就无法使用顺序。网上没有其他东西对我有帮助,因此任何反馈都是很棒的。

class Bst
{
    struct Node
    {
        T data;
        Node * left;
        Node * right;
        Node(T key) :data(key), left(nullptr), right(nullptr) {}
    };

    typedef void(*inorderPtr)(T &);
    typedef void(*preorderPtr)(T &);
    typedef void(*postorderPtr)(T &);

    Node * root;
    T & GetItem() const;
    void deleteNode(Node*);
    void printNode(Node*);
    void inorder(Node * root, void (*inorderPtr)(T &)) const;
    void preorder(Node * root) const;
    void postorder(Node * root) const;

public:

    Bst();
    ~Bst();
    Bst(const Bst<T> & source);
    const Bst<T> & operator = (const Node &);
    void insert(const T);
    void print();
    void inorder(void(*inorderPtr)(T &)) const;
    void printPreorder() const;
    void printPostorder() const;
};

基本bst的一些代码如下

template<class T>
inline T & Bst<T>::GetItem() const
{
    return data;
}

template<class T>
inline void Bst<T>::inorder(Node * root, void(*inorderPtr)(T &)) const
{
    if (root->left != nullptr)
    {
        inorder(root->left, inorderPtr);
    }

    inorderPtr(root->GetItem());

    if (root->right != nullptr)
    {
        inorder(root->right, inorderPtr);
    }
}

template<class T>
inline void Bst<T>::inorder(void(*inorderPtr)(T &)) const
{   
    inorder(this->root, inorderPtr);
}
int main()
{
        Bst<int> tree;

    for (int i = 0; i < 100; i++)
    {
        tree.insert(i);
    }

    tree.inorder();

}

主要是基础测试,但是inorder()遇到了麻烦;参数不足

2 个答案:

答案 0 :(得分:2)

您需要花费数周的时间来阅读有关C ++的更多信息。请记住, C ++是一种非常困难的编程语言(即使有5年的实践经验,您也不会成为C ++专家;我使用C ++编写代码,但我不是C ++专家;仅在地球上只有几十个)。而且,不要学习任何早于C++11且最好是C++17的东西(因为我们已经在2019年,所以最新的C ++编译器已经兼容C ++ 17,并且所有人都接受C ++ 11;如果您的编译器不了解C ++ 11,请更新您的C ++编译器。

(如果要求您使用C++03或更早的C ++而不是C ++ 11进行编码,则要求加薪,因为那时您使用的是过时的工具。今天,在2019年, C ++ 03中的编码类似于COBOL中的编码:它需要一种具有货币价值的罕见技能。)

因此,首先,读一本不错的C ++书,例如Programming -- Principles and Practice Using C++(由C ++的设计师编写)。然后查看某个C++ reference网站。另请阅读how to debug small programs(在这里非常相关)。

然后编译所有警告和调试信息。如果您的编译器是GCC,请至少使用g++ -Wall -g进行编译。 您会收到一条很好的诊断消息。请在您的问题中显示它

最后,您宣布inorder接受了一个参数,而在调用该参数时却没有给出任何参数(这样做的话前后矛盾):

   tree.inorder();
   //           ^     missing argument

您错误地问:

  

我正在创建一个二进制搜索树模板类,并且想要使用函数指针

正如我评论的那样,您应该避免使用function pointers (它们非常像C,而不是真正的C ++),并在std::function type中使用{ inorder,并在其declaration处传递一些匿名lambda expression。因为从概念上讲,应该传递的不是函数指针,而是call site(它将原始函数指针与数据,封闭值结合在一起),或者,如果不幸的是,您希望避免使用真正的指针。 C ++并与普通的C closure样式和procedural programming兼容,具有calling conventions,因此不仅传递原始函数指针,还传递一些客户端数据。

所以您真的想声明和定义(就像大多数callbacks一样)

template<class T>
inline void Bst<T>::inorder(std::function<void(T&)> fun) const;

(后来,作为优化,您可以将fun作为const C++ containers传递),并且可以像使用lambda表达式那样使用它,例如:

tree.inorder([](T& x) { std::cout << x << std::endl; });

我声称您的老师应该首先教您有关闭包的知识,以及如何以某种reference风格(在您的情况下很自然)很好地使用闭包,然后解释其实现以及以后,教功能指针。在大多数情况下,函数指针在C ++中已作废(但为了与C和C ++的过时版本兼容而存在)。

PS。您不了解的内容要花几十页来解释(因为C ++ functional programming非常复杂)。我们这里没有足够的空间(和时间来写它)。请花一个星期阅读一本优秀的C ++书

答案 1 :(得分:2)

假设您要打印树中每个节点的值:

void value_printer(int& value)
{
    std::cout << "Value is " << value << '\n';
}

int main()
{
    Bst<int> tree;

    // Insert nodes...

    tree.inorder(&value_printer);
}

您在value_printer调用中将指针传递到inorder函数。然后将为遍历中的每个节点调用该函数。

传递指针的函数当然可以做其他事情。而且,正如目前所声明的那样,您甚至可以修改树的值。

详细了解std::functionlambda expressions。另请参见this答案。