1. 数组和链表
数组
概念:数组是一种线性数据结构,其中元素按顺序存储并可以通过索引随机访问。
优点:
- 快速随机访问:O(1)时间复杂度。
- 内存连续,缓存友好。
缺点:
- 插入和删除操作效率低:O(n)时间复杂度。
- 大小固定,需要预定义。
使用场景:需要频繁访问元素且数组大小已知或可预估时。
public class ArrayExample {
public static void main(String[] args) {
// 声明和初始化数组
int[] array = new int[5];
// 给数组赋值
array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 4;
array[4] = 5;
// 访问数组元素
for (int i = 0; i < array.length; i++) {
System.out.println("Element at index " + i + ": " + array[i]);
}
// 动态数组(ArrayList)
ArrayList<Integer> dynamicArray = new ArrayList<>();
dynamicArray.add(1);
dynamicArray.add(2);
dynamicArray.add(3);
System.out.println("Dynamic Array Elements: " + dynamicArray);
}
}
链表
概念:链表是一种线性数据结构,其中每个元素(节点)包含一个数据值和一个指向下一个节点的引用。
优点:
- 插入和删除操作效率高:O(1)时间复杂度(在已知节点位置时)。
- 动态大小。
缺点:
- 随机访问效率低:O(n)时间复杂度。
- 需要额外的存储空间来存储指针。
使用场景:需要频繁插入和删除元素,且元素访问相对较少时。
class Node {
int data;
Node next;
Node(int data) {
this.data = data;
this.next = null;
}
}
class LinkedList {
Node head;
// 向链表添加元素
public void add(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
} else {
Node temp = head;
while (temp.next != null) {
temp = temp.next;
}
temp.next = newNode;
}
}
// 打印链表
public void printList() {
Node temp = head;
while (temp != null) {
System.out.print(temp.data + " -> ");
temp = temp.next;
}
System.out.println("null");
}
// 删除链表中的元素
public void delete(int key) {
Node temp = head, prev = null;
// 如果头节点就是要删除的节点
if (temp != null && temp.data == key) {
head = temp.next;
return;
}
// 搜索要删除的节点,记录前一个节点
while (temp != null && temp.data != key) {
prev = temp;
temp = temp.next;
}
// 如果没找到节点
if (temp == null) return;
// 断开节点
prev.next = temp.next;
}
public static void main(String[] args) {
LinkedList list = new LinkedList();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
System.out.println("Initial Linked List:");
list.printList();
list.delete(3);
System.out.println("Linked List after deletion:");
list.printList();
}
}
2. 栈和队列
栈:
先进后出(LIFO)结构。
主要操作:push(入栈),pop(出栈),top(获取栈顶元素), 时间复杂度都是O(1)
应用场景:函数调用管理(调用栈),表达式求值,括号匹配等。
import java.util.Stack;
public class StackExample {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
// 压入元素
stack.push(1);
stack.push(2);
stack.push(3);
// 查看栈顶元素
System.out.println("Top element: " + stack.peek());
// 弹出元素
System.out.println("Popped element: " + stack.pop());
System.out.println("Popped element: " + stack.pop());
// 检查栈是否为空
System.out.println("Is stack empty? " + stack.isEmpty());
// 打印剩余元素
System.out.println("Remaining elements in stack: " + stack);
}
}
队列:
先进先出(FIFO)结构。
主要操作:enqueue(入队),dequeue(出队),front(获取队头元素), 时间复杂度都是O(1)
应用场景:任务调度,广度优先搜索(BFS),打印任务管理等。
import java.util.LinkedList;
import java.util.Queue;
public class QueueExample {
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
// 添加元素
queue.add(1);
queue.add(2);
queue.add(3);
// 查看队头元素
System.out.println("Front element: " + queue.peek());
// 移除元素
System.out.println("Removed element: " + queue.poll());
System.out.println("Removed element: " + queue.poll());
// 检查队列是否为空
System.out.println("Is queue empty? " + queue.isEmpty());
// 打印剩余元素
System.out.println("Remaining elements in queue: " + queue);
}
}
3. 哈希表
概念
哈希表:通过哈希函数将键转换为数组的索引,并将值存储在相应的位置。哈希表的关键优势在于其常数时间复杂度O(1)的查找、插入和删除操作。
哈希函数:一种将输入(键)转换为固定大小整数的函数。好的哈希函数应尽量均匀地分布输入值,减少哈希冲突。
哈希冲突:当多个键被映射到相同索引时发生冲突。解决冲突的方法包括链地址法和开放地址法。
哈希表的优缺点
优点:
- 快速查找、插入和删除操作,平均时间复杂度为O(1)。
缺点:
- 需要处理哈希冲突。
- 性能依赖于哈希函数的质量。
- 需要足够大的内存来存储元素,以减少冲突。
import java.util.HashMap;
public class HashTableExample {
public static void main(String[] args) {
// 创建一个 HashMap
HashMap<String, Integer> map = new HashMap<>();
// 插入键值对
map.put("Alice", 30);
map.put("Bob", 25);
map.put("Charlie", 35);
// 查找元素
System.out.println("Alice's age: " + map.get("Alice"));
// 删除元素
map.remove("Bob");
// 检查是否包含某个键
if (map.containsKey("Charlie")) {
System.out.println("Charlie is in the map.");
}
// 遍历元素
for (String key : map.keySet()) {
System.out.println(key + ": " + map.get(key));
}
}
}