数据结构与算法实例(Java实现)
以下是涵盖数据结构与算法的Java实例,涉及数组、链表、栈、队列、树、图、排序、搜索等核心内容。每个实例包含简要说明和关键代码片段。
数组相关
反转数组
public static void reverseArray(int[] arr) {
int left = 0, right = arr.length - 1;
while (left < right) {
int temp = arr[left];
arr[left++] = arr[right];
arr[right--] = temp;
}
}
使用临时数组
通过创建一个新数组并按逆序填充元素,实现反转。时间复杂度为 O(n),空间复杂度为 O(n)。
public static int[] reverseWithTempArray(int[] arr) {
int[] reversed = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
reversed[i] = arr[arr.length - 1 - i];
}
return reversed;
}
原地交换法
直接在原数组上进行首尾交换,无需额外空间。时间复杂度为 O(n),空间复杂度为 O(1)。
public static void reverseInPlace(int[] arr) {
int start = 0;
int end = arr.length - 1;
while (start < end) {
int temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
start++;
end--;
}
}
使用 Java 集合工具类
借助 Collections.reverse()
方法反转数组,需先将数组转为列表。时间复杂度为 O(n),但转换过程可能增加额外开销。
public static void reverseWithCollections(Integer[] arr) {
List<Integer> list = Arrays.asList(arr);
Collections.reverse(list);
}
运行时间对比
- 临时数组法:适合需要保留原数组的场景,但空间占用较高。
- 原地交换法:效率最高,适合对原数组直接修改的情况。
- Collections 工具类:写法简洁,但可能因装箱/拆箱操作影响性能。
使用 Collections.reverse() 方法
对于 List
类型的数组,可以使用 Collections.reverse()
方法进行反转。这种方法简洁且高效。
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class ReverseArray {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Collections.reverse(list);
System.out.println(list); // [5, 4, 3, 2, 1]
}
}
使用临时数组进行反转
通过创建一个临时数组,将原数组的元素按逆序存入临时数组,从而实现反转。
public class ReverseArray {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
int[] reversed = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
reversed[i] = arr[arr.length - 1 - i];
}
System.out.println(Arrays.toString(reversed)); // [5, 4, 3, 2, 1]
}
}
原地反转数组
通过交换数组的首尾元素,实现原地反转,无需额外空间。
public class ReverseArray {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
int left = 0;
int right = arr.length - 1;
while (left < right) {
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
System.out.println(Arrays.toString(arr)); // [5, 4, 3, 2, 1]
}
}
使用 Stream API 反转数组
利用 Java 8 的 Stream API 实现数组反转,代码简洁但性能可能不如其他方法。
import java.util.Arrays;
import java.util.stream.IntStream;
public class ReverseArray {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
int[] reversed = IntStream.range(0, arr.length)
.map(i -> arr[arr.length - 1 - i])
.toArray();
System.out.println(Arrays.toString(reversed)); // [5, 4, 3, 2, 1]
}
}
使用 StringBuilder 反转字符串数组
对于字符串数组,可以先将数组转换为字符串,再通过 StringBuilder.reverse()
方法反转。
public class ReverseArray {
public static void main(String[] args) {
String[] arr = {"a", "b", "c", "d", "e"};
StringBuilder sb = new StringBuilder(Arrays.toString(arr));
String reversed = sb.reverse().toString();
System.out.println(reversed); // ]e ,d ,c ,b ,a[
}
}
查找数组中的最大值
public static int findMax(int[] arr) {
int max = arr[0];
for (int num : arr) {
if (num > max) max = num;
}
return max;
}
两数之和(哈希表优化)
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (map.containsKey(target - nums[i])) {
return new int[]{map.get(target - nums[i]), i};
}
map.put(nums[i], i);
}
return new int[0];
}
链表操作
单链表反转
public ListNode reverseList(ListNode head) {
ListNode prev = null;
while (head != null) {
ListNode next = head.next;
head.next = prev;
prev = head;
head = next;
}
return prev;
}
检测链表环(快慢指针)
public boolean hasCycle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) return true;
}
return false;
}
合并两个有序链表
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
ListNode curr = dummy;
while (l1 != null && l2 != null) {
if (l1.val < l2.val) {
curr.next = l1;
l1 = l1.next;
} else {
curr.next = l2;
l2 = l2.next;
}
curr = curr.next;
}
curr.next = l1 != null ? l1 : l2;
return dummy.next;
}
递归反转单链表
递归方法通过不断递归到链表末尾,然后反向修改指针实现反转。优点是代码简洁,但需要注意栈溢出风险(链表过长时)。
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode newHead = reverseList(head.next);
head.next.next = head;
head.next = null;
return newHead;
}
迭代反转单链表(双指针)
通过双指针(前驱prev
和当前curr
)遍历链表,逐个修改节点指向。空间复杂度为O(1),适合处理长链表。
public ListNode reverseList(ListNode head) {
ListNode prev = null, curr = head;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}
头插法反转单链表
利用虚拟头节点(dummy
),将遍历到的节点逐个插入到虚拟头节点之后,最终得到反转链表。
public ListNode reverseList(ListNode head) {
ListNode dummy = new ListNode(-1);
while (head != null) {
ListNode next = head.next;
head.next = dummy.next;
dummy.next = head;
head = next;
}
return dummy.next;
}
使用栈辅助反转
通过栈的“后进先出”特性反转链表。需额外空间,适合需要保留原链表的场景。
public ListNode reverseList(ListNode head) {
Stack<ListNode> stack = new Stack<>();
while (head != null) {
stack.push(head);
head = head.next;
}
ListNode dummy = new ListNode(-1);
ListNode curr = dummy;
while (!stack.isEmpty()) {
curr.next = stack.pop();
curr = curr.next;
}
curr.next = null;
return dummy.next;
}
反转链表区间(局部反转)
反转链表中指定区间内的节点,如LeetCode 92题。结合双指针和头插法实现局部反转。
public ListNode reverseBetween(ListNode head, int left, int right) {
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode pre = dummy;
for (int i = 0; i < left - 1; i++) {
pre = pre.next;
}
ListNode curr = pre.next;
for (int i = left; i < right; i++) {
ListNode next = curr.next;
curr.next = next.next;
next.next = pre.next;
pre.next = next;
}
return dummy.next;
}
每个方法适用于不同场景:递归简洁但需注意栈深度,迭代法通用高效,头插法适合部分问题,栈辅助可保留原链表,局部反转解决特定需求。
树结构
二叉树前序遍历(递归)
public void preorder(TreeNode root) {
if (root == null) return;
System.out.print(root.val + " ");
preorder(root.left);
preorder(root.right);
}
二叉树层序遍历(队列)
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
List<Integer> level = new ArrayList<>();
for (int i = 0; i < size; i++) {