主函数(Main)
package com.test;
import com.test.collection.ArrayList;
import com.test.collection.LinkedList;
import com.test.collection.Stack;
import com.test.collection.Queue;
public class Main {
public static void main(String[] args) {}
}
1. 顺序表(Array List)
顺序表是一种基于数组实现的数据结构,元素在内存中连续存储。
主要功能:
- 插入和删除:在指定位置插入或删除元素,时间复杂度为 O(n),因为需要移动其他元素。
- 访问元素:通过索引直接访问元素,时间复杂度为 O(1)。
- 动态扩展:当数组容量不足时,可以动态扩展数组大小
适用类型:
- 频繁随机访问:需要频繁按索引访问元素的场景。
- 元素数量固定或可预测:元素数量相对固定或可以预测,不需要频繁插入/删除操作。
- 内存使用紧凑:内存使用较为紧凑,不需要额外的指针开销。
package com.test.collection;
public class ArrayList<E> {
int size = 0;
private int capacity = 10;
private Object[] array = new Object[capacity];
public void add(E element, int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("插入位置非法,合法的插入位置为:0~" + size);
// 如果当前容量不足,进行扩容
if (size == capacity) {
resize();
}
// 将元素插入到指定位置,并移动后续元素
for (int i = size; i > index; i--) {
array[i] = array[i - 1];
}
array[index] = element;
size++;
}
private void resize() {
capacity *= 2;// 扩容
Object[] newArray = new Object[capacity];// 创建新的数组
System.arraycopy(array, 0, newArray, 0, size);// 复制元素到新数组
array = newArray;// 指向新数组
}
public String toString() {
System.out.println("ArrayList size: " + size);
StringBuilder builder = new StringBuilder();
for (int i = 0; i < size; i++) {
builder.append(array[i]).append(" ");
}
return builder.toString().trim();
}
@SuppressWarnings("unchecked")
public E remove(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("删除位置非法,合法的删除位置为:0~" + (size - 1));
}
E e = (E) array[index];
for (int i = index; i < size - 1; i++) {
array[i] = array[i + 1];
}
array[size - 1] = null; // 清除最后一个元素
size--; // 更新 size
return e; // 返回被删除的元素
}
public E get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("获取位置非法,合法的获取位置为:0~" + (size - 1));
}
return (E) array[index];
}
public boolean isEmpty() {
return size == 0;
}
}
2. 链表(Linked List)
链表是一种基于节点和指针实现的数据结构,元素在内存中不连续存储。
主要功能:
- 插入和删除:在指定位置插入或删除元素,时间复杂度为 O(1)(在已知节点的情况下)。
- 访问元素:需要从头节点开始遍历,时间复杂度为 O(n)。
- 动态扩展:无需预先分配固定大小,可以动态添加或删除节点。
适用类型
- 频繁插入/删除:需要频繁在中间位置插入或删除元素的场景。
- 元素数量不固定:元素数量不固定或难以预测,需要动态调整大小的场景。
- 内存使用灵活:内存使用较为灵活,不需要连续的内存空间。
示例代码(sample code):
public class LinkedList<E> {
private Node<E> head;
private int size;
private static class Node<E> {
E element;
Node<E> next;
Node(E element) {
this.element = element;
}
}
public void add(E element) {
Node<E> newNode = new Node<>(element);
if (head == null) {
head = newNode;
} else {
Node<E> current = head;
while (current.next != null) {
current = current.next;
}
current.next = newNode;
}
size++;
}
public E get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
Node<E> current = head;
for (int i = 0; i < index; i++) {
current = current.next;
}
return current.element;
}
public void remove(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
if (index == 0) {
head = head.next;
} else {
Node<E> current = head;
for (int i = 0; i < index - 1; i++) {
current = current.next;
}
current.next = current.next.next;
}
size--;
}
}
3. 栈(Stack)
栈是一种后进先出(LIFO)的数据结构。栈的主要操作包括压栈(push)、弹栈(pop)和查看栈顶元素(peek)。
主要功能:
- 压栈(push):将元素添加到栈顶。
- 弹栈(pop):移除并返回栈顶元素。
- 查看栈顶元素(peek):返回栈顶元素但不移除。
- 判空(isEmpty):检查栈是否为空。
适用类型:
- 函数调用和递归:栈在函数调用和递归中非常有用,因为函数调用和返回的过程本质上就是压栈和弹栈的过程。
- 表达式求值:栈可以用于中缀表达式转换为后缀表达式,以及后缀表达式的求值。
- 撤销操作:在文本编辑器或图形软件中,撤销操作通常使用栈来实现,每次修改操作都压入栈中,撤销时弹出栈顶操作。
- 浏览器历史记录:浏览器的前进和后退功能可以使用两个栈来实现,一个用于前进,一个用于后退。
- 括号匹配:栈可以用于检查括号是否匹配,例如检查表达式中的括号是否正确闭合。
示例代码(sample code):
public class Stack<E> {
private Node<E> top;
private int size;
private static class Node<E> {
E element;
Node<E> next;
Node(E element) {
this.element = element;
}
}
public void push(E element) {
Node<E> newNode = new Node<>(element);
newNode.next = top;
top = newNode;
size++;
}
public E pop() {
if (isEmpty()) {
throw new IllegalStateException("Stack is empty");
}
E element = top.element;
top = top.next;
size--;
return element;
}
public E peek() {
if (isEmpty()) {
throw new IllegalStateException("Stack is empty");
}
return top.element;
}
public boolean isEmpty() {
return size == 0;
}
}
4. 队列(Queue)
队列是一种先进先出(FIFO)的数据结构。队列的主要操作包括入队(enqueue)、出队(dequeue)和查看队头元素
主要功能:
- 入队(enqueue):将元素添加到队尾。
- 出队(dequeue):移除并返回队头元素。
- 查看队头元素(peek):返回队头元素但不移除。
- 判空(isEmpty):检查队列是否为空。
适用类型:
- 任务调度:操作系统中的任务调度通常使用队列来管理待执行的任务。
- 消息传递:在消息队列系统中,消息的发送和接收通常使用队列来实现。
- 广度优先搜索(BFS):在图的遍历中,广度优先搜索算法使用队列来存储待访问的节点。
- 打印任务队列:打印机管理打印任务时,通常使用队列来存储待打印的文档。
- 缓冲区:在数据流处理中,队列可以作为缓冲区来平衡生产和消费的速度。
public class Queue<E> {
private Node<E> head;
private Node<E> tail;
private int size;
private static class Node<E> {
E element;
Node<E> next;
Node(E element) {
this.element = element;
}
}
public void enqueue(E element) {
Node<E> newNode = new Node<>(element);
if (isEmpty()) {
head = newNode;
} else {
tail.next = newNode;
}
tail = newNode;
size++;
}
public E dequeue() {
if (isEmpty()) {
throw new IllegalStateException("Queue is empty");
}
E element = head.element;
head = head.next;
if (head == null) {
tail = null;
}
size--;
return element;
}
public E peek() {
if (isEmpty()) {
throw new IllegalStateException("Queue is empty");
}
return head.element;
}
public boolean isEmpty() {
return size == 0;
}
}