Menu
CoddyTech

二叉树

最后更新

二叉树是一种层级结构,每个节点最多有两个子节点,分别叫左子节点和右子节点。最顶端的节点是根节点,没有子节点的节点是叶子节点,从根节点到最深叶子节点的边数就是树的高度。和二叉搜索树不同,普通二叉树没有顺序规则,它只是一种形状。点击上方的“播放”,观察一棵树逐层填满,然后按中序(左、节点、右)被遍历。

很多结构都建立在二叉树之上:二叉搜索树、堆、表达式树等。遍历按照确定的顺序访问每个节点:中序、前序和后序是三种深度优先遍历,各自适合不同的任务。

术语

术语含义
根节点最顶端的节点,没有父节点
叶子节点没有子节点的节点
高度从根节点到叶子节点的最长路径(按边数计)
深度某个节点到根节点的距离
完全二叉树除最后一层外每层都是满的,最后一层从左到右填充

三种深度优先遍历

遍历方式顺序常见用途
中序遍历左、节点、右按顺序输出 BST
前序遍历节点、左、右复制或序列化一棵树
后序遍历左、右、节点删除一棵树或对其求值

示例演算

对由 [4, 2, 6, 1, 3, 5] 逐层填充构建的树进行中序遍历:

步骤当前节点操作
14访问 4 之前,先递归进入它的左子树
22访问 2 之前,先递归进入它的左子树
31叶子节点,没有左子节点,访问 1,输出 [1]
42左边处理完毕,访问 2,输出 [1, 2],然后递归进入右边
53叶子节点,访问 3,输出 [1, 2, 3]
64左子树处理完毕,访问 4,输出 [1, 2, 3, 4],然后递归进入右边
756 的左子节点,是叶子节点,访问 5,输出 [1, 2, 3, 4, 5]
86左边处理完毕,没有右子节点,访问 6,输出 [1, 2, 3, 4, 5, 6]

什么时候使用二叉树

适合使用的情况不适合使用的情况
需要表示本身就有层级的数据(文件系统、表达式树、DOM)数据是扁平的,用列表或数组就够了,树只会增加开销
需要有序操作,并且能保持树的平衡(BST 或自平衡树)需要按键平均 O(1) 查找,哈希表胜过任何树
需要按中序、前序或后序处理结构化数据把有序的节点插入不平衡的 BST,它会退化成 O(n) 的链表
范围查询或有序迭代很重要,而哈希表做不到内存紧张,每个节点除了数据还要存两个子节点指针

Binary Tree 代码

简洁、可运行的 Binary Tree 实现,提供 Python, JavaScript, Java, C++, C 版本。选择一种语言,复制代码,或在 Coddy 在线编辑器中直接打开。

Binary Tree 的 Python 代码

Python
1from collections import deque2
3
4class Node:5    def __init__(self, value):6        self.value = value7        self.left = None8        self.right = None9
10
11def insert(root, value):12    # Level-order insert: fill the first empty child slot found13    if root is None:14        return Node(value)15    queue = deque([root])16    while queue:17        node = queue.popleft()18        if node.left is None:19            node.left = Node(value)20            return root21        queue.append(node.left)22        if node.right is None:23            node.right = Node(value)24            return root25        queue.append(node.right)26
27
28def inorder(node):29    if node is None:30        return []31    return inorder(node.left) + [node.value] + inorder(node.right)32
33
34root = None35for value in [1, 2, 3, 4, 5, 6, 7]:36    root = insert(root, value)37
38print("Root:   ", root.value)39print("Inorder:", inorder(root))
在 Python 在线编辑器中运行这段代码

二叉树常见问题

二叉树和二叉搜索树有什么区别?

二叉树只是限制每个节点最多有两个子节点,没有顺序要求。二叉搜索树额外规定左子树中的值都更小、右子树中的值都更大,正是这条规则让查找变快。

什么是中序遍历?

中序遍历递归地先访问左子树,再访问节点本身,最后访问右子树。对于二叉搜索树,它会按升序输出所有值,这也是它最常被拿来演示的原因。

什么是完全二叉树?

完全二叉树除最后一层外,每一层都是满的,最后一层从左到右填充。这种形状让树可以紧凑地存放在数组中(不需要子节点指针),二叉堆就是这样实现的。

什么时候该用二叉树而不是数组或哈希表?
当数据天然具有层级结构,或者你需要范围查询、有序迭代这类哈希表做不到的有序操作时,就用树。如果只需要按键快速查找、不关心顺序,哈希表平均 O(1) 的访问胜过树;对于扁平数据,数组更简单,对缓存也更友好。
二叉树的高度和深度有什么区别?
深度从根节点往下量到某个节点,即从根节点到该节点路径上的边数。高度从某个节点往下量到它最深的叶子节点,所以整棵树的高度等于最深节点的深度。只有一个节点的树高度为 0,这个唯一节点的深度也是 0。
为什么不平衡的二叉树性能这么差?
在二叉搜索树中,查找、插入和删除的代价是 O(h),其中 h 是树的高度。当键按顺序插入时,树会变成一条直线,h 增长到 n,每个操作都退化为 O(n),并不比链表好。AVL 树、红黑树等自平衡树把高度保持在 O(log n),从而避免这种情况。
Coddy 编程语言插图

在 Coddy 掌握算法

开始