这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战。
树与图
许多求职者会觉得树与图的问题是最难对付的。检索这两种数据结构比数组或链表等线性数据结构要复杂得多。此外,在最坏情况和平均情况下,检索用时可能千差万别,对于任意算法,都要从这两方面进行评估。能够游刃有余地从无到有实现树或图,这是求职者必不可少的一种技能。
由于大部分人相较于图更熟悉树(树也简单一点),我们会先讨论树。因为树实际上是图的一种,所以这在某种程度上打乱了顺序。
树的类型
通过递归描述来理解树是一个不错的方法。树是由节点构成的数据结构。
- 每棵树都有一个根节点。(事实上,在图论中这并不必要,但是在编程中,特别是在编程面试中,我们通常这么做。)
- 根节点有0个或多个子节点。
- 每个子节点有0个或多个子节点,以此类推。
树不应包括环路。节点可以有序或无序排列,可以包含任何类型的值,同时也可以包括或不包括指向父节点的指针。
节点Node的一个简单实现如下:
1. class Node {
2. public String name;
3. public Node[] children;
4. }
你也可以使用一个名为Tree的类来封装该节点。在面试中,我们通常不使用Tree类。如果这会让你的代码更为简单或更为完善,可以使用该Tree类,尽管其很少能起到这样的作用。
1. class Tree {
2. public Node root;
3. }
树与图的问题充斥着模糊的细节和错误的假设。请务必注意以下的问题,并在必要时对此了然于胸。
树与二叉树
二叉树是指每个节点至多只有两个子节点的树。并不是所有的树都是二叉树。例如,下图所示就不是一棵二叉树,你可称其为三叉树。
有时候你可能会得到一棵不是二叉树的树。例如,假设使用树来表示一些电话号码。在这种情况下,你可以使用一个10叉树,其中每个树节点至多有10个子节点(每个节点代表一位数字)。
没有子节点的节点称为“叶节点”。
二叉树与二叉搜索树
二叉搜索树是二叉树的一种,该树的所有节点均需满足如下属性:全部左子孙节点 全部右子孙节点。
请注意:对于所有节点的子孙节点而言,该不等式都必须成立,其不仅仅局限于直接子节点。如图所示,左图为二叉搜索树,右图为非二叉搜索树,因为12在8的左边。
碰到二叉树问题时,许多求职者会假定面试官问的是二叉搜索树。此时务必问清楚二叉树是否为二叉搜索树。二叉搜索树应满足如下条件:对于任意节点,其左子孙节点小于或等于当前节点,而后者又小于所有右子孙节点。
平衡与不平衡
许多树是平衡的,但并非全都如此。树是否平衡要找面试官确认。请注意:平衡一棵树并不表示左子树和右子树的大小完全相同(如9.4.1.6节中的完美二叉树所示)。
思考此类问题的一个方法是,“平衡”树实际上多半意味着“不是非常不平衡”的树。它的平衡性足以确保执行insert和find操作可以在 的时间复杂度内完成,但其并不一定是严格意义上的平衡树。
平衡树的两种常见类型是红黑树(11.7节)和AVL树(11.6节),我们会在第11章中深入探讨。
完整二叉树
完整二叉树是二叉树的一种,其中除了最后一层外,树的每层都被完全填充。而树的最后一层,其节点是从左到右填充的。
满二叉树
满二叉树是二叉树的一种,其中每个节点都有零个或两个子节点,也就是说,不存在只有一个子节点的节点。
完美二叉树
完美二叉树既是完整二叉树,又是满二叉树。所有叶节点都处于同一层,而此层包含最大的节点数。
请注意:完美树在面试和现实生活中都极为罕见,因为一棵树必须正好有个节点才能满足这个条件(其中
是树的层数)。在面试中,不要事先假定一棵二叉树是完美的。