1. 数组 (Array)
数组是一种线性数据结构,元素在内存中连续存储,支持快速随机访问。访问元素的时间复杂度为O(1)O(1)O(1),但插入和删除可能需要O(n)O(n)O(n)时间(需移动元素)。
public class ArrayExample {
public static void main(String[] args) {
// 声明并初始化整型数组
int[] arr = {1, 2, 3, 4, 5};
// 访问元素(索引从0开始)
System.out.println("第三个元素: " + arr[2]); // 输出 3
// 修改元素
arr[2] = 10;
System.out.println("修改后第三个元素: " + arr[2]); // 输出 10
// 遍历数组
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
// 输出: 1 2 10 4 5
}
}
2. 链表 (Linked List)
链表由节点组成,每个节点包含数据和指向下一个节点的指针。插入和删除头节点的时间复杂度为O(1)O(1)O(1),但随机访问需要O(n)O(n)O(n)时间。链表适合动态大小数据。
// 定义链表节点类
class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
this.next = null;
}
}
// 链表操作示例
public class LinkedListExample {
public static void main(String[] args) {
// 创建链表: 1 -> 2 -> 3
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
// 插入新节点到头部
ListNode newNode = new ListNode(0);
newNode.next = head;
head = newNode; // 链表变为: 0 -> 1 -> 2 -> 3
// 删除头节点
head = head.next; // 链表变为: 1 -> 2 -> 3
// 遍历链表
ListNode current = head;
while (current != null) {
System.out.print(current.val + " ");
current = current.next;
}
// 输出: 1 2 3
}
}
3. 栈 (Stack)
栈是一种后进先出(LIFO)结构,只允许在栈顶进行插入(push)和删除(pop)操作。push和pop的时间复杂度均为O(1)O(1)O(1)。栈常用于函数调用和表达式求值。
import java.util.Stack; // 使用Java标准库
public class StackExample {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
// 压栈操作
stack.push(10);
stack.push(20);
stack.push(30); // 栈状态: [10, 20, 30] (30在栈顶)
// 弹栈操作
System.out.println("弹出元素: " + stack.pop()); // 输出 30
System.out.println("当前栈顶: " + stack.peek()); // 输出 20
// 检查栈是否为空
System.out.println("栈是否为空? " + stack.isEmpty()); // 输出 false
}
}
4. 队列 (Queue)
队列是一种先进先出(FIFO)结构,元素从队尾入队(enqueue),从队头出队(dequeue)。enqueue和dequeue的时间复杂度通常为O(1)O(1)O(1)。队列适用于任务调度。
import java.util.LinkedList;
import java.util.Queue; // 使用Java标准库
public class QueueExample {
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
// 入队操作
queue.add(10);
queue.add(20);
queue.add(30); // 队列状态: [10, 20, 30] (10在队头)
// 出队操作
System.out.println("出队元素: " + queue.poll()); // 输出 10
System.out.println("当前队头: " + queue.peek()); // 输出 20
// 检查队列是否为空
System.out.println("队列是否为空? " + queue.isEmpty()); // 输出 false
}
}
5. 二叉树 (Binary Tree)
二叉树每个节点最多有两个子节点(左和右)。插入、删除和搜索的时间复杂度在平衡树中为O(logn)O(\log n)O(logn),最坏情况下为O(n)O(n)O(n)。二叉树用于高效搜索和排序。
// 定义二叉树节点类
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int val) {
this.val = val;
this.left = null;
this.right = null;
}
}
// 二叉树操作示例
public class BinaryTreeExample {
public static void main(String[] args) {
// 创建二叉树: 根节点为1, 左子为2, 右子为3
TreeNode root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
// 插入新节点 (作为左子节点的左子节点)
root.left.left = new TreeNode(4);
// 前序遍历: 根 -> 左 -> 右
System.out.print("前序遍历: ");
preOrderTraversal(root); // 输出: 1 2 4 3
}
// 前序遍历辅助方法
public static void preOrderTraversal(TreeNode node) {
if (node == null) return;
System.out.print(node.val + " ");
preOrderTraversal(node.left);
preOrderTraversal(node.right);
}
}
6. 哈希表 (Hash Table)
哈希表使用哈希函数将键映射到存储位置,支持快速插入、删除和查找。平均时间复杂度为O(1)O(1)O(1),但哈希冲突时可能退化到O(n)O(n)O(n)。哈希表适用于键值对存储。
import java.util.HashMap; // 使用Java标准库
public class HashTableExample {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
// 插入键值对
map.put("apple", 10);
map.put("banana", 20);
map.put("orange", 30);
// 查找值
System.out.println("apple的数量: " + map.get("apple")); // 输出 10
// 删除键
map.remove("banana");
System.out.println("banana是否存在? " + map.containsKey("banana")); // 输出 false
// 遍历所有键值对
for (String key : map.keySet()) {
System.out.println(key + ": " + map.get(key));
}
// 输出: apple: 10, orange: 30
}
}
总结
以上数据结构覆盖了常见场景:
- 数组:适合快速访问,但大小固定。
- 链表:动态大小,插入删除高效。
- 栈和队列:管理数据顺序,分别用于LIFO和FIFO场景。
- 二叉树:高效搜索和排序基础。
- 哈希表:快速键值查找。
在实际应用中,Java标准库(如ArrayList
、LinkedList
、HashMap
)提供了优化实现。建议根据需求选择合适结构,例如搜索用树结构,缓存用哈希表。复杂度分析有助于预测性能,如平均查找时间在哈希表中为O(1)O(1)O(1),在二叉搜索树中为O(logn)O(\log n)O(logn)。