编写通用的遍历函数,可以灵活地处理具有不同参数的多个函数

时间:2019-05-01 02:02:08

标签: c++ function data-structures binary-search-tree

我想使用std :: function来帮助我运行一个遍历BST并调用参数化函数的通用遍历函数。

我的困难是参数化函数的参数有所不同。

因此,例如,我要归纳以下三个函数(它们的参数都不同)。

//populates an array with the values in the BST by traversing the BST
void LinkedBST<T>::populate(T const * const data, size_t & I, Node *x)

{
      data[i++] = x->val;
}

//insert unique values of another BST into "this" BST: traverses the other BST and inserts every value
void LinkedBST<T>::insert(Node *x)
{
      insert(x->val);
}

我不想为上述每个函数编写一个单独的遍历函数,而是希望将它们传递给一个通用遍历函数,例如:

void LinkedBST<T>::traverse(Node *x, auto func)
{
     if(x == nullptr)
          return;

     traverse(x->left, func);
     func( <parameters> );
     traverse(x->right, func);
}

有没有办法做到这一点?如果有,您能帮我吗?

谢谢:)

2 个答案:

答案 0 :(得分:2)

通常,您将需要找到一种方法来标准化所有遍历回调的签名。一种选择是使用lambda,并使用lambda捕获来减少函数参数的数量。

void LinkedBST<T>::populate(T const * const data, size_t & I)
{
    traverse(root, [&](Node * x) {
            data[i++] = x->val;
        });
}

请注意,compare不能使用相同的遍历函数,因为您需要同时遍历两棵树。还不清楚insert应该做什么,但是从注释看来,它也需要同时遍历。

答案 1 :(得分:1)

一种解决方案是对遍历函数进行模板化以获取一个函数对象。然后,无需在traverse函数中指定参数,而是将这些参数移至函数对象,并让函数对象的operator()在调用时处理详细信息:

template <typename func>
void LinkedBST<T>::traverse(Node *x, func fn)
{
     if(x == nullptr)
          return;

     traverse(x->left, fn);
     fn(x->val);
     traverse(x->right, fn);
}

struct some_func
{
   int param1;
   int param2;
   int param3;

   some_func(int p1, int p2, int p3) : param1(p1), param2(p2), param3(p3) {}
   void operator()(int node_value) 
   {
      std::cout << "The node value is " << node_value << "\n";
      // the parameters are param1, param2, param3
   }
};

调用operator()(调用函数)后,现在具有节点值以及在对象内部设置的所有参数。

然后可以执行以下操作:

Node *node_ptr;
//...
LinkedBST<int> the_list;
//...
some_func f(1,2,3);  // we want to use 1,2,3 as the parameters to the custom function
the_list.traverse(node_ptr, f);

这里是simplified version,显示了通过使用虚拟类的基础知识。


您还可以通过此技术使用lambda:

Node *node_ptr;
//...
LinkedBST<int> the_list;
//...
int arg1=1, arg2=2, arg3=3;
the_list.traverse(node_ptr, 
                  [&](int node_value){std::cout << "The node value is " << 
                                      node_value << "\n" << arg1 << " " << 
                                      arg2 << " " << arg3;});