数据结构 | 定义 | 节点特点 | 遍历方式 | 常见操作 | 时间复杂度(平均) | 时间复杂度(最坏) | 空间复杂度(最坏) | 与其他结构关系 | 应用场景 |
---|---|---|---|---|---|---|---|---|---|
树 | 有根节点,分层级,包含父子、兄弟节点及子树关系的非线性数据结构 | 每个节点可有多条分支,连接多个子节点 | 无特定统一遍历顺序,可按需求自定义遍历逻辑 | 查找、插入、删除(操作复杂度因树结构不同差异大) | 查找、插入、删除: O ( n ) O(n) O(n)(无特殊结构时) | 查找、插入、删除: O ( n ) O(n) O(n) | O ( n ) O(n) O(n)(取决于树中节点数量) | Linked List是特殊化的Tree,Tree是特殊化的Graph | 文件目录结构、组织架构图等场景 |
二叉树 | 每个节点最多有两个子节点的树结构 | 最多两个子节点,分别为左子节点和右子节点 | 前序(根 - 左 - 右)、中序(左 - 根 - 右)、后序(左 - 右 - 根) | 查找、插入、删除(操作复杂度与树的形态有关) | 查找、插入、删除: O ( n ) O(n) O(n)(普通二叉树) | 查找、插入、删除: O ( n ) O(n) O(n)(例如单支树情况) | O ( n ) O(n) O(n)(与树的节点数相关) | 是树的特殊形式 | 在一些简单的决策树模型、算术表达式树中有应用 |
二叉搜索树 | 空树或满足左子树节点值小于根节点值,右子树节点值大于根节点值,且左右子树也为二叉搜索树的二叉树 | 除具备二叉树节点特征外,节点值具有有序性 | 中序遍历结果为升序排列,还有前序、后序遍历 | 查询、插入、删除 | 查询、插入、删除: O ( log n ) O(\log n) O(logn) | 查询: O ( n ) O(n) O(n)(树严重不平衡时) 插入、删除: O ( n ) O(n) O(n)(树严重不平衡时) |
O ( n ) O(n) O(n)(取决于节点数量) | 是二叉树的特殊形式 | 用于数据搜索、排序场景,如数据库索引、符号表管理 |
前序遍历、中序遍历和后序遍历是二叉树的三种常见遍历方式,它们的定义和特点如下:
A
(根节点),左子树节点B
,右子树节点C
,前序遍历的顺序就是A
、B
、C
。A
(根节点),左子树节点B
,右子树节点C
,中序遍历的顺序就是B
、A
、C
。B
、C
、A
。这三种遍历方式都是基于递归的思想实现的,在实际应用中,可以根据具体需求选择合适的遍历方式来处理二叉树相关的问题。同时,也可以通过栈或其他数据结构将递归遍历转换为非递归的形式进行实现。
def preorder(self, root):
if root:
self.traverse_path.append(root.val)
self.preorder(root.left)
self.preorder(root.right)
def inorder(self, root):
if root:
self.inorder(root.left)
self.traverse_path.append(root.val)
self.inorder(root.right)
def postorder(self, root):
if root:
self.postorder(root.left)
self.postorder(root.right)
self.traverse_path.append(root.val)
二叉搜索树(Binary Search Tree,BST) ,也叫二叉查找树、二叉排序树 ,它要么是空树,要么是满足以下性质的二叉树:
对二叉搜索树进行中序遍历(左子树 - 根节点 - 右子树 ),会得到一个递增的有序序列 。
这种结构在数据操作上具有优势:
与二分查找思想类似,通过和当前节点值比较,若目标值小于当前节点值,在左子树查找;若大于,则在右子树查找 。平均时间复杂度为 O ( log n ) O(\log n) O(logn)( n n n为节点数) ,但树不平衡退化为链表时,时间复杂度会变为 O ( n ) O(n) O(n) 。
新节点总是作为叶子节点插入。从根节点开始比较,若新节点值小于当前节点值,往当前节点左子树插入;若大于,则往右子树插入 ,直到找到合适位置。平均时间复杂度 O ( log n ) O(\log n) O(logn) 。
二叉搜索树应用广泛,像数据库系统、文件系统常利用它实现高效的数据检索和管理 。 但它存在不平衡问题,为解决该问题,有AVL树、红黑树等自平衡二叉搜索树变种 。
给定二叉树的根节点 root
,按中序遍历(左子树 - 根节点 - 右子树)顺序,返回树中所有节点的值。
# 定义二叉树节点类
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def inorderTraversal(self, root):
result = []
def inorder(root):
if root:
inorder(root.left)
result.append(root.val)
inorder(root.right)
inorder(root)
return result
inorder
实现递归。先判断根节点 root
是否存在,若存在,先递归调用 inorder(root.left)
处理左子树,此时会层层深入左子树,直到叶子节点。然后将当前根节点的值 root.val
添加到结果列表 result
,最后递归调用 inorder(root.right)
处理右子树 。给定一个二叉树的根节点 root
,按照前序遍历(根节点 - 左子树 - 右子树)的顺序,返回树中所有节点的值。
Python递归解法
# 定义二叉树节点类
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def preorderTraversal(self, root):
result = []
def preorder(root):
if root:
result.append(root.val)
preorder(root.left)
preorder(root.right)
preorder(root)
return result
preorder
中,先判断 root
是否存在。若存在,首先将根节点的值 root.val
加入结果列表 result
,这体现前序遍历先访问根节点的特点。然后递归调用 preorder(root.left)
访问左子树,再递归调用 preorder(root.right)
访问右子树 。给定一个 N 叉树的根节点 root
,按照后序遍历(左子树 - 右子树 - 根节点 ,这里 N 叉树的多个子树也按类似顺序,先遍历完所有子树,最后访问根节点)的顺序,返回树中所有节点的值。
Python递归解法
# 定义N叉树节点类
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children if children is not None else []
class Solution:
def postorder(self, root):
result = []
def post(root):
if root:
for child in root.children:
post(child)
result.append(root.val)
post(root)
return result
post
实现递归。先判断 root
是否存在,若存在,遍历根节点的所有子节点 root.children
,对每个子节点递归调用 post(child)
,这相当于先处理完所有子树。处理完子树后,将根节点的值 root.val
添加到结果列表 result
,符合后序遍历的逻辑。给定一个 N 叉树的根节点 root
,按照前序遍历(根节点 - 子树 ,依次访问完根节点后,再按顺序访问各个子树)的顺序,返回树中所有节点的值。
Python递归解法
# 定义N叉树节点类
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children if children is not None else []
class Solution:
def preorder(self, root):
result = []
def pre(root):
if root:
result.append(root.val)
for child in root.children:
pre(child)
pre(root)
return result
pre
中,先判断 root
是否存在。若存在,首先将根节点的值 root.val
加入结果列表 result
,这体现前序遍历先访问根节点的特点。然后遍历根节点的所有子节点 root.children
,对每个子节点递归调用 pre(child)
,依次访问各个子树。给定一个二叉树的根节点 root
,判断其是否为有效的二叉搜索树 。有效二叉搜索树需满足:左子树的所有节点的值均小于根节点的值;右子树的所有节点的值均大于根节点的值;且左、右子树也分别为二叉搜索树。
# 定义二叉树节点类
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def isValidBST(self, root):
def check(root, min_val, max_val):
if not root:
return True
if root.val <= min_val or root.val >= max_val:
return False
return check(root.left, min_val, root.val) and check(root.right, root.val, max_val)
return check(root, float('-inf'), float('inf'))
check
进行递归验证。check
函数接收当前节点 root
,以及当前节点值的取值范围 min_val
和 max_val
。每次递归时,先检查当前节点 root
的值是否在合理范围内(大于 min_val
且小于 max_val
),若不满足则返回 False
。然后对左子树递归调用 check
,并更新取值范围为 (min_val, root.val)
,对右子树递归调用 check
,更新取值范围为 (root.val, max_val)
。如果所有节点都满足条件,则返回 True
。n
是二叉树的节点数,因为需要遍历每个节点进行判断。空间复杂度在最好情况下为 O ( log n ) O(\log n) O(logn) (树高度平衡时,递归调用栈深度与树高相关 ),最坏情况下为 O ( n ) O(n) O(n) (树退化为链表时,递归调用栈深度等于节点数) 。