一、 二分查找算法
二分查找是一种高效的查找算法,适用于已排序
的数组。它通过将待查找区间不断缩小为一半来查找目标值,直到找到目标值或确定不存在。
二分查找算法代码如下:
public class BinarySearch {
public static int binarySearch(int[] arr, int target) {
int left = 0;
int right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
public static void main(String[] args) {
int[] arr = {1, 3, 5, 7, 9, 11, 13, 15};
int target = 7;
int result = binarySearch(arr, target);
if (result != -1) {
System.out.println("目标值在数组中的索引为:" + result);
} else {
System.out.println("目标值不在数组中");
}
}
}
二、 哈希表查找算法
哈希表是一种基于哈希函数
实现的数据结构,能够快速地查找、插入和删除元素。哈希表通过哈希函数将键映射到存储位置,实现了常数时间复杂度的查找操作。
哈希表查找算法代码如下:
import java.util.HashMap;
public class HashMapSearch {
public static void main(String[] args) {
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("Alice", 25);
hashMap.put("Bob", 30);
hashMap.put("Charlie", 35);
String target = "Bob";
if (hashMap.containsKey(target)) {
int age = hashMap.get(target);
System.out.println(target + "的年龄为:" + age);
} else {
System.out.println("未找到对应信息");
}
}
}
三、 树结构的查找算法
在树结构中,常用的查找算法包括二叉搜索树查找
、平衡二叉搜索树(如AVL树、红黑树)查找
等。这些算法能够在树结构中快速地查找目标值。
1. 二叉搜索树BST
二叉搜索树是一种二叉树,其中每个节点的值大于其左子树
中的所有节点的值,小于其右子树
中的所有节点的值。
代码如下:
class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val) {
this.val = val;
this.left = null;
this.right = null;
}
}
public class BinarySearchTree {
private TreeNode root;
public BinarySearchTree() {
this.root = null;
}
// 查找操作
public TreeNode search(int val) {
return searchRec(root, val);
}
private TreeNode searchRec(TreeNode root, int val) {
if (root == null || root.val == val) {
return root;
}
if (val < root.val) {
return searchRec(root.left, val);
} else {
return searchRec(root.right, val);
}
}
// 插入操作
public void insert(int val) {
root = insertRec(root, val);
}
private TreeNode insertRec(TreeNode root, int val) {
if (root == null) {
return new TreeNode(val);
}
if (val < root.val) {
root.left = insertRec(root.left, val);
} else if (val > root.val) {
root.right = insertRec(root.right, val);
}
return root;
}
public static void main(String[] args) {
BinarySearchTree bst = new BinarySearchTree();
bst.insert(5);
bst.insert(3);
bst.insert(7);
TreeNode result = bst.search(3);
if (result != null) {
System.out.println("找到节点:" + result.val);
} else {
System.out.println("未找到节点");
}
}
}
2. AVL树
AVL树是一种自平衡的二叉搜索树,它保持了左右子树的高度差不超过1
,从而保持树的平衡。在AVL树中进行查找、插入和删除操作的时间复杂度为O(log n)
。
AVL树的代码如下:
// AVL树的实现可以使用现有的库,例如Java中的TreeMap和TreeSet等
import java.util.TreeMap;
public class AVLTreeExample {
public static void main(String[] args) {
TreeMap<Integer, String> avlTree = new TreeMap<>();
avlTree.put(5, "apple");
avlTree.put(3, "banana");
avlTree.put(7, "orange");
String result = avlTree.get(3);
if (result != null) {
System.out.println("找到节点:" + result);
} else {
System.out.println("未找到节点");
}
}
}
3. 红黑树
红黑树是一种自平衡的二叉搜索树,它通过在每个节点上添加颜色属性(红色或黑色)来保持平衡。红黑树的特性使得其在插入和删除操作时能够保持树的平衡。
代码如下:
enum Color {
RED, BLACK
}
class Node {
int val;
Color color;
Node left, right, parent;
public Node(int val) {
this.val = val;
this.color = Color.RED;
this.left = null;
this.right = null;
this.parent = null;
}
}
public class RedBlackTree {
private Node root;
private Node nil;
public RedBlackTree() {
nil = new Node(-1);
nil.color = Color.BLACK;
root = nil;
}
private void leftRotate(Node x) {
Node y = x.right;
x.right = y.left;
if (y.left != nil) {
y.left.parent = x;
}
y.parent = x.parent;
if (x.parent == nil) {
root = y;
} else if (x == x.parent.left) {
x.parent.left = y;
} else {
x.parent.right = y;
}
y.left = x;
x.parent = y;
}
private void rightRotate(Node y) {
Node x = y.left;
y.left = x.right;
if (x.right != nil) {
x.right.parent = y;
}
x.parent = y.parent;
if (y.parent == nil) {
root = x;
} else if (y == y.parent.left) {
y.parent.left = x;
} else {
y.parent.right = x;
}
x.right = y;
y.parent = x;
}
private void insertFixup(Node z) {
while (z.parent.color == Color.RED) {
if (z.parent == z.parent.parent.left) {
Node y = z.parent.parent.right;
if (y.color == Color.RED) {
z.parent.color = Color.BLACK;
y.color = Color.BLACK;
z.parent.parent.color = Color.RED;
z = z.parent.parent;
} else {
if (z == z.parent.right) {
z = z.parent;
leftRotate(z);
}
z.parent.color = Color.BLACK;
z.parent.parent.color = Color.RED;
rightRotate(z.parent.parent);
}
} else {
Node y = z.parent.parent.left;
if (y.color == Color.RED) {
z.parent.color = Color.BLACK;
y.color = Color.BLACK;
z.parent.parent.color = Color.RED;
z = z.parent.parent;
} else {
if (z == z.parent.left) {
z = z.parent;
rightRotate(z);
}
z.parent.color = Color.BLACK;
z.parent.parent.color = Color.RED;
leftRotate(z.parent.parent);
}
}
}
root.color = Color.BLACK;
}
public void insert(int val) {
Node z = new Node(val);
Node y = nil;
Node x = root;
while (x != nil) {
y = x;
if (z.val < x.val) {
x = x.left;
} else {
x = x.right;
}
}
z.parent = y;
if (y == nil) {
root = z;
} else if (z.val < y.val) {
y.left = z;
} else {
y.right = z;
}
z.left = nil;
z.right = nil;
z.color = Color.RED;
insertFixup(z);
}
public static void main(String[] args) {
RedBlackTree rbTree = new RedBlackTree();
rbTree.insert(5);
rbTree.insert(3);
rbTree.insert(7);
}
}
上面代码实现了一个简单的红黑树,包括左旋、右旋和插入修复等操作。
-
红黑树的节点定义:
在代码中,定义了一个节点类 Node ,包含了节点的值 val 、颜色 color 、左子节点 left 、右子节点 right 和父节点 parent 。初始化时,将哨兵节点 nil 定义为黑色,并将根节点 root 初始化为哨兵节点。 -
左旋和右旋操作:
代码中实现了左旋和右旋操作,用于在插入节点后调整红黑树的结构,保持平衡。 -
插入修复操作 insertFixup :
在插入节点后,可能会破坏红黑树的性质,需要通过插入修复操作来修复。插入修复操作主要分为两种情况:- Case 1: 当父节点和叔父节点都为红色时,将父节点和叔父节点的颜色修改为黑色,祖父节点的颜色修改为红色,然后将当前节点指向祖父节点,继续修复。
- Case 2: 当父节点为红色,叔父节点为黑色,并且当前节点是父节点的右子节点时,需要进行左旋操作;当父节点为红色,叔父节点为黑色,并且当前节点是父节点的左子节点时,需要进行右旋操作。
-
插入操作 insert :
在插入节点时,首先找到插入位置,并将新节点的颜色设为红色。然后调用插入修复操作 insertFixup 来修复可能破坏的红黑树性质。 -
节点颜色的保证:
红黑树通过以下规则来保证节点的颜色是红色或黑色:- 根节点必须为黑色。
- 红色节点的子节点必须为黑色。
- 从根节点到叶子节点的每条路径上,黑色节点的数量必须相同。
- 不能有两个相邻的红色节点。
通过这些规则,红黑树能够保证节点的颜色是红色或黑色,从而保持树的平衡和性质。这样的设计使得红黑树能够高效地支持插入、删除和查找等操作。