Whay need Binary Tree
已经有数组、链表了,为什么还需要二叉树?
什么数据结构能在保证顺序的同时,又能快速完成查找、插入和删除呢?
有序数组和哈希表都做不到这一点。
这时就该二叉查找树出场了。
Character
二叉树的特点:
- 一棵树有且一个根节点;
- 每个节点有且一个上级(根节点除外),两个下级(叫做左子节点,右子节点);
- 一个节点的“左”子树中的值都小于节点本身,“右”子树中的值都大于节点本身 , 这个规律贯彻整棵树的所有节点;
二叉树图例:
Implementing with Java:
// 定义一个树节点类
class TreeNode {
int val; // 节点的值
TreeNode left; // 左子节点
TreeNode right; // 右子节点
// 节点构造函数
TreeNode(int val) {
this.val = val;
this.left = null;
this.right = null;
}
}
// 定义二叉树类
public class BinaryTree {
private TreeNode root; // 二叉树的根节点
// 二叉树构造函数
public BinaryTree() {
root = null;
}
// 向二叉树添加节点
public void add(int val) {
root = addRecursive(root, val);
}
// 递归添加节点
private TreeNode addRecursive(TreeNode current, int val) {
if (current == null) {
return new TreeNode(val);
}
if (val < current.val) {
current.left = addRecursive(current.left, val);
} else if (val > current.val) {
current.right = addRecursive(current.right, val);
} // 如果值已经存在,则不添加
return current;
}
// 在二叉树中查找一个值
public boolean containsNode(int val) {
return containsNodeRecursive(root, val);
}
// 递归查找值
private boolean containsNodeRecursive(TreeNode current, int val) {
if (current == null) {
return false;
}
if (val == current.val) {
return true;
}
return val < current.val
? containsNodeRecursive(current.left, val)
: containsNodeRecursive(current.right, val);
}
// 删除二叉树中的节点
public void delete(int val) {
root = deleteRecursive(root, val);
}
// 递归删除节点
private TreeNode deleteRecursive(TreeNode current, int val) {
if (current == null) {
return null;
}
if (val == current.val) {
// 节点找到,进行删除
// 情况1: 没有子节点
if (current.left == null && current.right == null) {
return null;
}
// 情况2: 只有一个子节点
if (current.right == null) {
return current.left;
}
if (current.left == null) {
return current.right;
}
// 情况3: 有两个子节点
// 找到右子树中最小的值,用这个值替换要删除的节点,然后删除那个最小的值的节点
int smallestValue = findSmallestValue(current.right);
current.val = smallestValue;
current.right = deleteRecursive(current.right, smallestValue);
return current;
}
if (val < current.val) {
current.left = deleteRecursive(current.left, val);
return current;
}
current.right = deleteRecursive(current.right, val);
return current;
}
// 找到最小值(辅助删除操作)
private int findSmallestValue(TreeNode root) {
return root.left == null ? root.val : findSmallestValue(root.left);
}
// 修改二叉树中的节点,这里的"修改"是删除再添加的方式
public void update(int oldValue, int newValue) {
delete(oldValue); // 删除旧值
add(newValue); // 添加新值
}
// 中序遍历打印二叉树
public void inorderPrint() {
inorderPrintRecursive(root);
}
// 递归中序遍历
private void inorderPrintRecursive(TreeNode node) {
if (node != null) {
inorderPrintRecursive(node.left);
System.out.print(node.val + " ");
inorderPrintRecursive(node.right);
}
}
// 主函数,用于测试二叉树的功能
public static void main(String[] args) {
BinaryTree tree = new BinaryTree();
// 添加节点
tree.add(5);
tree.add(3);
tree.add(7);
tree.add(2);
tree.add(4);
tree.add(6);
tree.add(8);
// 打印二叉树
tree.inorderPrint(); // 应输出: 2 3 4 5 6 7 8
System.out.println();
// 查找节点
System.out.println(tree.containsNode(4)); // 应输出: true
System.out.println(tree.containsNode(9)); // 应输出: false
// 删除节点
tree.delete(7);
// 打印删除节点后的二叉树
tree.inorderPrint(); // 应输出: 2 3 4 5 6 8
System.out.println();
// 修改节点(将5修改为9)
tree.update(5, 9);
// 打印修改节点后的二叉树
tree.inorderPrint(); // 应输出: 2 3 4 6 8 9
}
}
打印输出:
总结:
二叉搜索树的特性是左子节点的值小于父节点的值,右子节点的值大于父节点的值。这些操作通常采用递归方式实现。
Requirement Scenarios
我之前想使用二叉树去制作一个存储公司员工职级的表(维持上下级关系的层级结构),其实更合适的数据结构可能是多叉树或者类似组织结构的图。在这个结构中,每个节点可以有多个子节点,这代表一个CEO下面有多个经理,经理下有多个下属。
要使用二叉树存储员工信息并查询员工的上级和下级信息,您需要设计一个更复杂的数据结构。二叉树的每个节点将需要存储员工的信息,包括名字和可能的其他信息,比如职位。
标准的二叉搜索树并不适用于这种类型的层级查询,因为它只按一个键(例如员工ID或名字)排序,而不是层级结构。
知道一个数据结构很重要,当遇到一个新业务场景适配什么数据结构也是一门知识。