C 搜索二叉搜索树最有效的方法是什么?

C 搜索二叉搜索树最有效的方法是什么?,c,binary-tree,binary-search-tree,binary-search,C,Binary Tree,Binary Search Tree,Binary Search,我见过很多在二叉排序树中搜索的算法,但它们都使用相同的方法:递归。我知道递归与循环相比是昂贵的,因为每次我们调用搜索函数时,都会为该方法创建一个新的堆栈框架,如果二叉搜索树太大,它最终会占用大量内存 为什么我们不能像这样搜索二进制搜索树: while (root!=NULL) { if (root->data==data) return 0; else if (data > root->data) root=root->ri

我见过很多在二叉排序树中搜索的算法,但它们都使用相同的方法:递归。我知道递归与循环相比是昂贵的,因为每次我们调用搜索函数时,都会为该方法创建一个新的堆栈框架,如果二叉搜索树太大,它最终会占用大量内存

为什么我们不能像这样搜索二进制搜索树:

while (root!=NULL)
{
    if (root->data==data)
        return 0;
    else if (data > root->data)
        root=root->right;
    else
        root=root->left;
}

我认为这种方法比递归方法更快更有效,如果我错了,请纠正我

是的,这是正常的方法。

是的,这是正常的方法。

可能你的方法-这是在C中编写代码的常用方法-可能更快,但你应该进行基准测试,因为一些C编译器(例如,最近使用
gcc-O2
调用时)能够作为跳转进行优化(并在寄存器中传递值)。尾部调用优化意味着被调用方重用帧(因此调用堆栈保持有界)。请参阅

FWIW,在OCaml(或Scheme,或Haskell,或最常见的Lisp实现)中,您将编写一个尾部递归调用,并且您知道编译器正在将其优化为跳转

递归并不总是比循环慢(尤其是尾部调用)。这是编译器优化的问题


阅读和。如果您只懂C,请学习一些经常使用尾部调用的函数式语言(Ocaml、Haskell或Scheme with…)。阅读Scheme中的相关内容。

也许您的方法(这是用C编写代码的常用方法)可能会更快,但您应该进行基准测试,因为有些C编译器(例如,当使用
gcc-O2
..调用时,最新版本)能够作为跳转(并在寄存器中传递值)进行优化。尾部调用优化意味着被调用方重用帧(因此调用堆栈保持有界)。请参阅

FWIW,在OCaml(或Scheme,或Haskell,或最常见的Lisp实现)中,您将编写一个尾部递归调用,并且您知道编译器正在将其优化为跳转

递归并不总是比循环慢(尤其是尾部调用)。这是编译器优化的问题


阅读和。如果您只懂C,请学习一些经常使用尾部调用的函数式语言(Ocaml、Haskell或Scheme with…)。阅读Scheme中的内容。

理论上,您的解决方案和递归解决方案都是相同的。理论上,它们都是O(log n)。如果您希望以秒为单位衡量性能,则需要付诸实践,编写这两种方法的代码(迭代、递归),运行它们并测量运行时间。

理论上,您的解决方案和递归解决方案都具有相同的性能。理论上,它们都是O(log n)。如果您希望以秒为单位衡量性能,您需要付诸实践,编写这两种方法的代码(迭代、递归),运行它们并测量运行时间。

您应该进行基准测试。我不需要时间来测量和比较,我只是在理论上问:)你应该进行基准测试。我不需要时间来测量和比较,我只是在理论上问:)那么,正如你提到的,堆栈将为整个递归保留一帧@Basile@flashdisk:是的,如果编译器执行此优化,则尾部位置的递归调用不会分配新堆栈帧。正如Basile所说,大多数函数式语言都要求编译器在可能的情况下始终优化尾部调用,而在C语言中这是不保证的(因此,如果您希望安全,应该迭代地编写代码)。顺便说一句,如果你有一些额外的时间,看看经典的文章“lambda,最终的goto”-它很好地解释了为什么递归函数不一定比命令循环效率低。所以,正如你提到的,堆栈将为整个递归保留一个帧@Basile@flashdisk:是的,如果编译器执行此优化,则尾部位置的递归调用不会分配新堆栈帧。正如Basile所说,大多数函数式语言都要求编译器在可能的情况下始终优化尾部调用,而在C语言中这是不保证的(因此,如果您希望安全,应该迭代地编写代码)。顺便说一句,如果你有额外的时间,请阅读经典文章“lambda,终极goto”-它很好地解释了为什么递归函数的效率不一定比命令式循环低。我认为这两种方法是正常的:)我认为这两种方法是正常的:)