我想知道二叉树的特定应用是什么。你能举一些真实的例子吗?
答案 0 :(得分:393)
关于二进制树的性能的争论是没有意义的 - 它们不是数据结构,而是一系列数据结构,都具有不同的性能特征。虽然不平衡二进制树确实比自平衡二进制树执行搜索更糟糕,但有许多二叉树(例如二进制尝试)其中“balance”没有任何意义。
map
和set
对象。 二进制树比n-ary树更常用于搜索的原因是n-ary树更复杂,但通常没有提供真正的速度优势。
在具有m
个节点的(平衡)二叉树中,从一个级别移动到下一个级别需要一次比较,并且有log_2(m)
个级别,总共log_2(m)
个比较。
相反,n-ary树需要log_2(n)
比较(使用二分搜索)才能移动到下一个级别。由于总共有log_n(m)
个级别,因此搜索总共需要log_2(n)*log_n(m)
= log_2(m)
次比较。因此,虽然n-ary树更复杂,但它们在总体比较方面没有任何优势。
(但是,n-ary树在利基情况下仍然有用。立即想到的例子是quad-trees和其他空间分区树,其中分区空间每层仅使用两个节点会使逻辑变得不必要地复杂;并且B-trees在许多数据库中使用,其中限制因素不是每个级别进行多少次比较,而是可以同时从硬盘驱动器加载多少个节点)
答案 1 :(得分:253)
当大多数人谈论二叉树时,他们往往不会考虑二元搜索树,所以我先介绍一下。
非平衡二叉搜索树实际上对于教育学生数据结构更有用。这是因为,除非数据以相对随机的顺序进入,否则树很容易退化为最坏情况的形式,这是一个链表,因为简单的二叉树不平衡。
一个很好的例子:我曾经不得不修复一些将其数据加载到二叉树中进行操作和搜索的软件。它以排序的形式写出数据:
Alice
Bob
Chloe
David
Edwina
Frank
因此,在重新阅读时,最后得到以下树:
Alice
/ \
= Bob
/ \
= Chloe
/ \
= David
/ \
= Edwina
/ \
= Frank
/ \
= =
这是简并形式。如果你在那棵树上寻找弗兰克,你必须在找到他之前搜索所有六个节点。
二进制树在平衡它们时变得非常有用。这涉及通过其根节点旋转子树,以便任何两个子树之间的高度差小于或等于1.将这些名称一次一个地添加到平衡树中将给出以下序列:
1. Alice
/ \
= =
2. Alice
/ \
= Bob
/ \
= =
3. Bob
_/ \_
Alice Chloe
/ \ / \
= = = =
4. Bob
_/ \_
Alice Chloe
/ \ / \
= = = David
/ \
= =
5. Bob
____/ \____
Alice David
/ \ / \
= = Chloe Edwina
/ \ / \
= = = =
6. Chloe
___/ \___
Bob Edwina
/ \ / \
Alice = David Frank
/ \ / \ / \
= = = = = =
实际上,当添加条目时,您可以看到整个子树向左旋转(在步骤3和6中),这为您提供了一个平衡的二叉树,其中最坏情况查找是O(log N)
而不是O(N
)退化形式给出的。在任何时候,最高NULL(=
)与最低值相差不超过一个级别。并且,在上面的最后一棵树中,您只需查看三个节点(Chloe
,Edwina
,最后是Frank
)就可以找到Frank。
当然,当你使它们成为平衡的多路树而不是二进制树时,它们会变得更有用。这意味着每个节点包含多个项目(从技术上讲,它们包含N个项目和N + 1个指针,二叉树是具有1个项目和2个指针的单向多路树的特殊情况)。
使用三向树,最终得到:
Alice Bob Chloe
/ | | \
= = = David Edwina Frank
/ | | \
= = = =
这通常用于维护项目索引的键。我编写了针对硬件优化的数据库软件,其中节点的大小与磁盘块的大小完全相同(例如,512字节),并且您可以将尽可能多的密钥放入单个节点中。在这种情况下,指针实际上是记录数字到与索引文件分开的固定长度记录的直接访问文件中(因此只需寻找{{{{}}就可以找到记录号X
1}})。
例如,如果指针是4个字节且密钥大小为10,则512字节节点中的密钥数为36.这是36个密钥(360个字节)和37个指针(148个字节),总计为每个节点浪费了508字节,浪费了4个字节。
多路密钥的使用引入了两阶段搜索的复杂性(多路搜索找到正确的节点结合小的顺序(或线性二进制)搜索以找到节点中的正确密钥)但是减少磁盘I / O的优势远远超过了这一点。
我认为没有理由为内存结构执行此操作,您最好坚持使用平衡二叉树并保持代码简单。
另请注意,当您的数据集很小时,X * record_length
优于O(log N)
的优势并不会真正出现。如果您使用多向树将十五个人存储在地址簿中,那可能会有些过分。当您在过去十年中存储来自十万客户的每个订单之类的东西时,优势就会出现。
大O符号的重点是指示当O(N)
接近无穷大时会发生什么。有些人可能不同意,但如果你确定数据集会保持在一定的规模以下,只要没有别的东西可供使用,甚至可以使用冒泡排序: - )
对于二叉树的其他用途,有很多,例如:
鉴于我为搜索树生成了多少解释,我不愿详细讨论其他问题,但如果您愿意,这应该足以研究它们。
答案 2 :(得分:56)
二叉树是一种树数据结构,其中每个节点最多有两个子节点,通常区分为“左”和“右”。具有子节点的节点是父节点,子节点可以包含对其父节点的引用。在树之外,通常会引用“根”节点(所有节点的祖先)(如果存在)。可以通过从根节点开始并反复跟随对左子节点或右子节点的引用来到达数据结构中的任何节点。在二叉树中,每个节点的最大度为2。
二叉树非常有用,因为正如您在图片中看到的那样,如果要在树中找到任何节点,则只需要查看最多6次。例如,如果要搜索节点24,则应从根目录开始。
此搜索如下所示:
您可以看到第一遍可以排除整个树的一半节点。第二个是左子树的一半。这使得搜索非常有效。如果这是在4 十亿元素上完成的,那么您最多只需要搜索32次。因此,树中包含的元素越多,搜索效率就越高。
删除可能会变得复杂。如果节点有0或1个子节点,那么只需移动一些指针即可排除要删除的节点。但是,您无法轻松删除包含2个子节点的节点。所以我们采取捷径。假设我们想要删除节点19。
由于试图确定将左右指针移动到哪里并不容易,我们找到一个用它替换它。我们去左侧的子树,尽可能向右走。这为我们提供了我们想要删除的节点的下一个最大价值。
现在我们复制所有18个内容,左右指针除外,并删除原来的18个节点。
为了创建这些图像,我实现了一个AVL树,一个自平衡树,这样在任何时间点,树在叶节点(没有子节点的节点)之间至多有一个级别的差异。这样可以防止树变得歪斜并保持最长O(log n)
次搜索时间,并且插入和删除所需的时间会更长。
这是一个示例,展示了我的AVL树如何保持自己的紧凑和平衡。
在排序数组中,查找仍然需要O(log(n))
,就像树一样,但随机插入和删除将采用O(n)而不是树O(log(n))
。一些STL容器使用这些性能特征,因此插入和移除时间最多为O(log n)
,这非常快。其中一些容器是map
,multimap
,set
和multiset
。
答案 3 :(得分:55)
答案 4 :(得分:11)
主要应用是binary search trees。这些是一种数据结构,其中搜索,插入和删除都非常快(约log(n)
次操作)
答案 5 :(得分:10)
答案 6 :(得分:9)
未提及的二叉树的一个有趣示例是递归计算的数学表达式。从实际的角度来看,它基本上是无用的,但它是一种有趣的方式来思考这些表达。
基本上,树的每个节点都有一个值本身固有的值,或者通过对其子节点值进行操作来递归计算。
例如,表达式(1+3)*2
可以表示为:
*
/ \
+ 2
/ \
1 3
要评估表达式,我们要求父级的值。该节点依次从其子节点,加号运算符和仅包含“2”的节点获取其值。加号运算符依次从值为“1”和“3”的子元素中获取值,并将它们相加,将4返回到乘法节点,返回8。
这种二叉树的使用在某种意义上类似于反向抛光表示法,因为执行操作的顺序是相同的。还有一点需要注意的是,它不一定必须是二叉树,它只是最常用的运算符是二进制的。在最基本的层面上,这里的二叉树实际上只是一种非常简单的纯函数式编程语言。
答案 7 :(得分:8)
最常见的应用之一是以有序的形式有效地存储数据,以便快速访问和搜索存储的元素。例如,C ++标准库中的std::map
或std::set
。
二叉树作为数据结构对于表达式解析器和表达式求解器的各种实现非常有用。
它也可以用于解决一些数据库问题,例如索引。
通常,二叉树是特定基于树的数据结构的一般概念,可以构造具有不同属性的各种特定类型的二叉树。
答案 8 :(得分:7)
我不认为“纯”二叉树有任何用处。 (除教育用途外) 平衡二叉树(例如Red-Black trees或AVL trees)更有用,因为它们可以保证O(logn)操作。正常的二叉树可能最终成为一个列表(或几乎列表),并且在使用大量数据的应用程序中并不真正有用。
平衡树通常用于实现地图或集合。 它们也可以用于在O(nlogn)中进行排序,即使存在更好的方法也可以。
也可以使用搜索/插入/删除Hash tables,这通常比二叉搜索树具有更好的性能(平衡与否)。
如果需要搜索/插入/删除和排序,那么(平衡的)二进制搜索树将有用的应用程序将是有用的。给定一个现成的平衡树,Sort可以就地(几乎忽略递归所需的堆栈空间)。它仍然是O(nlogn)但是具有较小的常数因子并且不需要额外的空间(除了新数组之外,假设必须将数据放入数组中)。另一方面,哈希表无法排序(至少不能直接排序)。
也许它们在一些复杂的算法中也很有用,但是我没有想到什么。如果我发现更多,我将编辑我的帖子。
其他树木如f.e. B+trees广泛用于数据库
答案 9 :(得分:7)
二叉树的应用:
答案 10 :(得分:6)
在C ++ STL中,以及其他语言中的许多其他标准库,如Java和C#。二叉搜索树用于实现集合和映射。
答案 11 :(得分:5)
二叉树最重要的应用之一是平衡二进制搜索树,如:
这些类型的树具有以下特性:通过在每次插入或删除节点时执行旋转等操作,左子树和右子树的高度差异保持较小。
由于这个原因,树的总高度仍然是log n的顺序,并且在O(log n)时间内执行诸如搜索,插入和删除节点之类的操作。 C ++的STL还以集合和映射的形式实现这些树。
答案 12 :(得分:4)
它们可以用作快速排序数据的方法。将数据插入O(log(n))的二叉搜索树中。然后遍历树以对它们进行排序。
答案 13 :(得分:2)
BST是一种二叉树,在Unix内核中用于管理一组虚拟内存区域(VMA)。
答案 14 :(得分:1)
java.util.Set
答案 15 :(得分:1)
在现代硬件上,由于缓存和空间行为不良,二叉树几乎总是次优的。这也适用于(半)平衡变体。如果你找到它们,那就是性能不计算的地方(或由比较功能支配),或者更有可能出于历史或无知的原因。
答案 16 :(得分:1)
您的程序语法,或者就此而言,可以使用二叉树(尽管不一定)解析许多其他内容,例如自然语言。
答案 17 :(得分:1)
几乎所有数据库(和类似数据库的)程序都使用二叉树来实现其索引系统。
答案 18 :(得分:-1)
使用二叉树表示AST的编译器可以使用已知算法 解析树像postorder,inorder。程序员不需要提出它自己的算法。 因为源文件的二叉树高于n-ary树,所以它的构建需要更多时间。 采取这种生产: selstmnt:=“if”“(”expr“)”stmnt“ELSE”stmnt 在二叉树中,它将具有3个级别的节点,但是n-ary树将具有1个级别(chids)
这就是为什么基于Unix的操作系统很慢的原因。