数据结构-有序二叉树
一、基本概念
有序二叉树(又称二叉搜索树)是一种特殊的二叉树,其左子树的所有节点值均小于根节点值,右子树的所有节点值均大于等于根节点值,且左右子树也分别为有序二叉树。
二、核心功能及实现
1. 插入节点(insert)
功能:向有序二叉树中插入新节点,维持树的有序性
实现逻辑:
若树为空,新节点作为根节点
若树非空,从根节点开始比较
新值小于当前节点值:向左子树查找插入位置
新值大于等于当前节点值:向右子树查找插入位置
找到空位置后插入新节点
public void insert(int num) {Node node = new Node(num);if(root==null) {root=node;return;}Node index = root;while(true) {if(index.value>num) {if(index.left==null) {index.left=node;return;}index=index.left;}else {if(index.right==null) {index.right=node;return;}index=index.right;}}
}
2. 遍历操作
用于按特定顺序访问树中所有节点
(1)前序遍历(beforeOrder)
顺序:根节点 → 左子树 → 右子树
实现:递归方式
public void beforeOrder(Node node) {if(node==null) return;System.out.println(node.value); // 访问根节点beforeOrder(node.left); // 遍历左子树beforeOrder(node.right); // 遍历右子树
}
(2)中序遍历(inOrder)
顺序:左子树 → 根节点 → 右子树
特点:对于有序二叉树,中序遍历结果为升序排列
实现:递归方式
public void inOrder(Node node) {if(node==null) return;inOrder(node.left); // 遍历左子树System.out.println(node.value); // 访问根节点inOrder(node.right); // 遍历右子树
}
(3)后序遍历(afterOrder)
顺序:左子树 → 右子树 → 根节点
实现:递归方式
public void afterOrder(Node node) {if(node==null) return;afterOrder(node.left); // 遍历左子树afterOrder(node.right); // 遍历右子树System.out.println(node.value); // 访问根节点
}
(4)层序遍历(levelOrder)
顺序:按层次从左到右访问节点
实现:使用队列辅助
public void levelOrder() {Queue<Node> queue = new LinkedList<Node>();queue.add(root);while(!queue.isEmpty()) {Node index = queue.poll();System.out.println(index.value); // 访问当前节点if(index.left!=null) queue.add(index.left); // 左子节点入队if(index.right!=null) queue.add(index.right); // 右子节点入队}
}
3. 查找操作
(1)查找节点(search)
功能:查找指定值的节点并返回
实现逻辑:
从根节点开始比较
目标值等于当前节点值:返回当前节点
目标值小于当前节点值:向左子树查找
目标值大于当前节点值:向右子树查找
未找到返回 null
public Node search(int num) {if(root==null) return null;Node index = root;while(index!=null) {if(index.value==num) return index;else if(index.value<num) index = index.right;else index = index.left;}return null;
}
(2)查找父节点(searchParent)
功能:查找指定值节点的父节点
实现逻辑:
根节点无父节点,直接返回 null
遍历树,检查当前节点的左右子节点是否为目标节点
找到则返回当前节点(父节点),未找到返回 null
public Node searchParent(int num) {if(root.value==num) return null; // 根节点无父节点Node index = root;while(index!=null) {if((index.left!=null&&index.left.value==num)||(index.right!=null&&index.right.value==num)) {return index;}else if(index.value>num) index=index.left;else index=index.right;}return null;
}
4. 删除节点(delete)
功能:删除指定值的节点,维持树的有序性
分类处理:
删除叶子节点(无左右子节点):
直接将父节点对应指针置为 null
若为根节点,直接置空根节点
删除有两个子节点的节点:
找到该节点右子树中最小的节点(最左节点)
用最小节点值替换待删除节点值
删除找到的最小节点
删除只有一个子节点的节点:
将待删除节点的子节点连接到其父节点
若为根节点,直接用子节点替换根节点
public void delete(int num) {Node target = search(num); // 找到目标节点if(target==null) {System.out.println("未找到该节点");return;}Node parent = searchParent(num); // 找到父节点// 处理三种删除情况(代码见原实现)
}
三、总结
有序二叉树通过维持节点值的有序性,实现了高效的插入、查找和删除操作(理想情况下时间复杂度为 O (log n))。上述实现包含了二叉搜索树的核心功能,通过不同的遍历方式可以按需求访问树中节点,删除操作则需要根据节点的子节点情况进行分类处理以维持树的结构。
广度遍历(BFS)和深度遍历(DFS)是两种核心的图 / 树遍历算法,用于系统性地访问数据结构中的所有节点,核心区别在于访问顺序和实现方式。
1. 广度遍历(Breadth-First Search, BFS)
核心定义:从起始节点出发,先访问当前节点的所有邻接节点(同层节点),再逐层向下访问下一层节点,类似 “逐层扩散” 的搜索方式。
关键特点
顺序:先同层、后下层,保证 “先发现的节点先访问”(先进先出,FIFO)。
实现依赖:必须使用队列(Queue) 存储待访问节点,避免重复访问需标记已访问节点。
典型应用:
求无权图的最短路径(如迷宫最短出口);
层次化处理(如打印二叉树的每一层、社交网络 “好友的好友” 推荐)。
示例(二叉树)
假设有如下二叉树:
1/ \2 3/ \
4 5
BFS 访问顺序:1 → 2 → 3 → 4 → 5
(先访问根节点 1,再访问同层的 2、3,最后访问下一层的 4、5)。
2. 深度遍历(Depth-First Search, DFS)
核心定义:从起始节点出发,优先沿一条路径 “钻到底”(访问到最深层节点),无法继续时回溯,再探索其他路径,类似 “一条路走到黑” 的搜索方式。
关键特点
顺序:先深度、后回溯,遵循 “后发现的节点先访问”(后进先出,LIFO)。
实现依赖:可使用栈(Stack) 或递归(递归本质是调用栈),同样需标记已访问节点避免循环。
典型应用:
拓扑排序(如课程安排问题);
迷宫路径搜索(需探索所有可能路径);
连通性检测(如判断图中两点是否连通)。
常见变种(以二叉树为例)
DFS 在二叉树中根据 “根节点、左子树、右子树” 的访问顺序,分为三种常见形式:
前序遍历(Pre-order):根 → 左 → 右,访问顺序:
1 → 2 → 4 → 5 → 3
;中序遍历(In-order):左 → 根 → 右,访问顺序:
4 → 2 → 5 → 1 → 3
(二叉搜索树中此顺序为 “升序”);后序遍历(Post-order):左 → 右 → 根,访问顺序:
4 → 5 → 2 → 3 → 1
。
BFS 与 DFS 核心区别对比
对比维度 | 广度遍历(BFS) | 深度遍历(DFS) |
---|---|---|
访问顺序 | 逐层扩散(先同层,后下层) | 深度优先(先到底,再回溯) |
数据结构依赖 | 队列(Queue) | 栈(Stack)或递归(调用栈) |
空间复杂度 | 取决于最宽层的节点数 | 取决于树 / 图的深度 |
适用场景 | 求无权最短路径、层次化处理 | 拓扑排序、全路径搜索、连通性检测 |
通过 “队列 vs 栈” 的实现差异,可快速区分两种算法:BFS 是 “排队访问”,DFS 是 “栈顶优先探索”。