遍历bst使用函数指针的正确方法
Correct way to use function pointers for traversal bst
我正在创建一个二叉搜索树模板 class,并想为中序遍历函数使用函数指针,我对函数指针没问题,但由于某种原因我不知道如何使用中序一次代码已经到位。网上没有太多其他东西对我有帮助,所以任何反馈都会很棒。
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() 时遇到问题;参数不足
您需要花数周时间阅读更多有关 C++ 的内容。请记住,C++ 是一种非常难的编程语言(即使练习 5 年,您也不会成为 C++ 专家;我用 C++ 编写代码,但我不是专家; C++ 专家在地球上可能只有几十个)。并且不要学习任何早于 C++11 and preferably C++17 的东西(因为我们是 2019 年,所以最新的 C++ 编译器已经兼容 C++17,并且它们都接受 C++11;如果你的编译器不知道关于 C++11,更新你的 C++ 编译器)。
(如果你需要在C++03 or some earlier C++, instead of C++11, ask for a pay raise, because then you are using obsolete tools. Today, in 2019, coding in C++03 is like coding in COBOL中编码:它需要一个具有货币价值的稀有技能。)
所以首先,阅读一本很好的 C++ 书籍,例如 Programming -- Principles and Practice Using C++ (by the designer of C++). Then look into some C++ reference site. Read also how to debug small programs(这里非常相关)。
然后,使用所有警告和调试信息进行编译。如果你的编译器是 GCC,至少用 g++ -Wall -g
编译。 您会收到一条很好的诊断信息。请在你的问题中显示它。
最后,你声明你的 inorder
接受一个参数,而你在调用它时没有给出任何参数(这样做是不一致的):
tree.inorder();
// ^ missing argument
你问错了:
I am creating a binary search tree template class, and want to use function pointers
正如我评论的那样,您应该避免function pointers (they are so C like, not genuine C++), and use some std::function
type in the declaration of that inorder
, and pass perhaps some anonymous lambda expression at its call site. Because what you should pass conceptually is not a function pointer, but a closure (which combines a raw function pointer with data, the closed values), or, if you unfortunately want to avoid genuine C++ and stay compatible with plain C procedural programming style and calling conventions, have callbacks,因此不仅要传递原始函数指针,还要传递一些客户端数据。
所以你真的想声明和定义(像大多数 C++ containers 那样)
template<class T>
inline void Bst<T>::inorder(std::function<void(T&)> fun) const;
(稍后,作为 优化 ,您可以将 fun
作为 const
reference 传递)并且您将使用它(与一个 lambda 表达式)例如:
tree.inorder([](T& x) { std::cout << x << std::endl; });
我声称你的老师应该首先教你闭包以及如何以某种 functional programming 风格很好地使用它们(这在你的情况下很自然),然后解释它们的 实现 也和后来的函数指针教学。在大多数情况下,函数指针在 C++ 中已过时(但它们的存在是为了与 C 和 C++ 的过时版本兼容)。
PS。不明白的地方要解释几十页(因为C++type system很复杂)。我们这里没有那么多space(还有时间写)。请花一周时间读一本好的 C++ 书。
假设您要打印树中每个节点的值:
void value_printer(int& value)
{
std::cout << "Value is " << value << '\n';
}
int main()
{
Bst<int> tree;
// Insert nodes...
tree.inorder(&value_printer);
}
您在 inorder
调用中传递了指向 value_printer
函数的指针。然后将为遍历中的每个节点调用该函数。
当然,您传递指针的函数可以做其他事情。正如目前声明的那样,您甚至可以修改树的值。
了解有关 std::function
and lambda expressions. See also 答案的更多信息。
我正在创建一个二叉搜索树模板 class,并想为中序遍历函数使用函数指针,我对函数指针没问题,但由于某种原因我不知道如何使用中序一次代码已经到位。网上没有太多其他东西对我有帮助,所以任何反馈都会很棒。
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() 时遇到问题;参数不足
您需要花数周时间阅读更多有关 C++ 的内容。请记住,C++ 是一种非常难的编程语言(即使练习 5 年,您也不会成为 C++ 专家;我用 C++ 编写代码,但我不是专家; C++ 专家在地球上可能只有几十个)。并且不要学习任何早于 C++11 and preferably C++17 的东西(因为我们是 2019 年,所以最新的 C++ 编译器已经兼容 C++17,并且它们都接受 C++11;如果你的编译器不知道关于 C++11,更新你的 C++ 编译器)。
(如果你需要在C++03 or some earlier C++, instead of C++11, ask for a pay raise, because then you are using obsolete tools. Today, in 2019, coding in C++03 is like coding in COBOL中编码:它需要一个具有货币价值的稀有技能。)
所以首先,阅读一本很好的 C++ 书籍,例如 Programming -- Principles and Practice Using C++ (by the designer of C++). Then look into some C++ reference site. Read also how to debug small programs(这里非常相关)。
然后,使用所有警告和调试信息进行编译。如果你的编译器是 GCC,至少用 g++ -Wall -g
编译。 您会收到一条很好的诊断信息。请在你的问题中显示它。
最后,你声明你的 inorder
接受一个参数,而你在调用它时没有给出任何参数(这样做是不一致的):
tree.inorder();
// ^ missing argument
你问错了:
I am creating a binary search tree template class, and want to use function pointers
正如我评论的那样,您应该避免function pointers (they are so C like, not genuine C++), and use some std::function
type in the declaration of that inorder
, and pass perhaps some anonymous lambda expression at its call site. Because what you should pass conceptually is not a function pointer, but a closure (which combines a raw function pointer with data, the closed values), or, if you unfortunately want to avoid genuine C++ and stay compatible with plain C procedural programming style and calling conventions, have callbacks,因此不仅要传递原始函数指针,还要传递一些客户端数据。
所以你真的想声明和定义(像大多数 C++ containers 那样)
template<class T>
inline void Bst<T>::inorder(std::function<void(T&)> fun) const;
(稍后,作为 优化 ,您可以将 fun
作为 const
reference 传递)并且您将使用它(与一个 lambda 表达式)例如:
tree.inorder([](T& x) { std::cout << x << std::endl; });
我声称你的老师应该首先教你闭包以及如何以某种 functional programming 风格很好地使用它们(这在你的情况下很自然),然后解释它们的 实现 也和后来的函数指针教学。在大多数情况下,函数指针在 C++ 中已过时(但它们的存在是为了与 C 和 C++ 的过时版本兼容)。
PS。不明白的地方要解释几十页(因为C++type system很复杂)。我们这里没有那么多space(还有时间写)。请花一周时间读一本好的 C++ 书。
假设您要打印树中每个节点的值:
void value_printer(int& value)
{
std::cout << "Value is " << value << '\n';
}
int main()
{
Bst<int> tree;
// Insert nodes...
tree.inorder(&value_printer);
}
您在 inorder
调用中传递了指向 value_printer
函数的指针。然后将为遍历中的每个节点调用该函数。
当然,您传递指针的函数可以做其他事情。正如目前声明的那样,您甚至可以修改树的值。
了解有关 std::function
and lambda expressions. See also