二叉搜索树的结构
二叉搜索树是一种特殊的二叉树,它具有以下性质:
- 对于任意一个节点,其左子树中所有节点的值都小于它,右子树中所有节点的值都大于它。
- 中序遍历二叉搜索树可以得到一个递增的有序序列。
由于二叉搜索树的这些特性,它在查找、插入、删除等操作上都有很高的效率。在查找时,我们可以利用二叉搜索树的有序性进行二分查找,时间复杂度为O(logn);在插入和删除时,我们只需要对树进行简单的旋转和平衡调整即可,时间复杂度也为O(logn)。
二叉搜索树的实现可以使用链表或者数组等数据结构,通常我们使用链表来实现。在Java中,我们可以使用TreeNode类来表示二叉搜索树的节点,该类包含了节点值、左子节点、右子节点等信息。在实现时,需要注意二叉搜索树的节点值不能重复,如果有重复值则需要进行相应处理。
一些常用的操作
- 查找操作(递归实现)
二叉搜索树的查找操作可以采用递归的方式实现,其基本思路是:如果当前节点为空或者节点值等于目标值,则返回当前节点;如果目标值小于当前节点的值,则在左子树中查找;否则在右子树中查找。具体代码如下:
public TreeNode searchBST(TreeNode root, int val) {
if (root == null || root.val == val) {
return root;
}
if (val < root.val) {
return searchBST(root.left, val);
} else {
return searchBST(root.right, val);
}
}
- 插入操作(递归实现)
二叉搜索树的插入操作可以采用递归的方式实现,其基本思路是:如果当前节点为空,则将新节点插入到当前位置;如果目标值小于当前节点的值,则在左子树中插入;否则在右子树中插入。具体代码如下:
public TreeNode insertIntoBST(TreeNode root, int val) {
if (root == null) {
return new TreeNode(val);
}
if (val < root.val) {
root.left = insertIntoBST(root.left, val);
} else {
root.right = insertIntoBST(root.right, val);
}
return root;
}
- 删除操作(递归实现)
二叉搜索树的删除操作可以采用递归的方式实现,其基本思路是:如果当前节点为空,则返回空节点;如果目标值小于当前节点的值,则在左子树中删除;如果目标值大于当前节点的值,则在右子树中删除;如果目标值等于当前节点的值,则需要进行具体的删除操作。具体代码如下:
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) {
return null;
}
if (key < root.val) {
root.left = deleteNode(root.left, key);
} else if (key > root.val) {
root.right = deleteNode(root.right, key);
} else {
if (root.left == null) {
return root.right;
} else if (root.right == null) {
return root.left;
}
TreeNode minNode = getMin(root.right);
root.val = minNode.val;
root.right = deleteNode(root.right, minNode.val);
}
return root;
}
private TreeNode getMin(TreeNode node) {
while (node.left != null) {
node = node.left;
}
return node;
}
以下是一些常用操作的总结
public class BinarySearchTree {
// 定义二叉搜索树的节点
private class Node {
int val;
Node left;
Node right;
public Node(int val) {
this.val = val;
this.left = null;
this.right = null;
}
}
private Node root; // 根节点
public BinarySearchTree() {
root = null;
}
// 查找操作
public boolean search(int val) {
Node curr = root;
while (curr != null) {
if (curr.val == val) {
return true;
} else if (curr.val > val) {
curr = curr.left;
} else {
curr = curr.right;
}
}
return false;
}
// 插入操作
public void insert(int val) {
root = insertNode(root, val);
}
private Node insertNode(Node node, int val) {
if (node == null) {
return new Node(val);
}
if (node.val > val) {
node.left = insertNode(node.left, val);
} else if (node.val < val) {
node.right = insertNode(node.right, val);
}
return node;
}
// 删除操作
public void delete(int val) {
root = deleteNode(root, val);
}
private Node deleteNode(Node node, int val) {
if (node == null) {
return null;
}
if (node.val == val) {
if (node.left == null) {
return node.right;
} else if (node.right == null) {
return node.left;
} else {
Node minNode = getMin(node.right);
node.val = minNode.val;
node.right = deleteNode(node.right, minNode.val);
}
} else if (node.val > val) {
node.left = deleteNode(node.left, val);
} else {
node.right = deleteNode(node.right, val);
}
return node;
}
// 获取最小节点
private Node getMin(Node node) {
while (node.left != null) {
node = node.left;
}
return node;
}
// 获取最大节点
private Node getMax(Node node) {
while (node.right != null) {
node = node.right;
}
return node;
}
}
做题总结关键词
- 中序遍历(Inorder Traversal):一种二叉树的遍历方式,先遍历左子树,再遍历根节点,最后遍历右子树。
- 递归(Recursion):一种函数调用自身的编程技巧,常用于解决需要重复执行同样操作的问题。
- 迭代(Iteration):一种循环执行的编程结构,与递归相对,通常用于遍历数据结构或执行重复的计算。
- 二分查找(Binary Search):一种快速查找有序数组中特定元素的算法。
- Morris遍历:一种对二叉树进行遍历的算法,不需要使用递归或者栈,空间复杂度为O(1)。
- 旋转(Rotation):一种对二叉搜索树进行平衡的操作,包括左旋和右旋两种方式。
- DFS(Depth-First Search):深度优先搜索,是一种遍历图和树的算法,沿着一个路径遍历直到最深处,再回溯到前一个节点继续遍历。
- BFS(Breadth-First Search):广度优先搜索,是一种遍历图和树的算法,按照距离从近到远的顺序遍历节点。
- 双指针(Two Pointers):一种常用于数组或链表操作的算法技巧,利用两个指针在数组或链表中同时向前或向后移动。
- 快速选择(Quick Select):一种基于快速排序的算法,用于在未排序的数组中查找第k小/大的元素。
- 动态规划(Dynamic Programming):一种用于解决具有重复子问题和最优子结构性质的问题的算法,通常使用递推式求解。
- 分治算法(Divide and Conquer):一种将问题分解为更小子问题的算法,分别解决子问题,最终合并得到原问题的解。