内容来自刘宇波老师算法与数据结构体系课
1、动态数组
| 在这里新创建一个数组类,对 Java 语言中的原始数组进行封装,使得它可以动态的扩容和缩容 |
| Java 语言中也有类似的实现,叫 ArrayList,我们创建的数组类是它的简化版本,下面是代码实现 |
| |
| |
| |
| public class Array<E> { |
| |
| private E[] data; |
| private int size; |
| |
| public Array(int capacity) { |
| data = (E[]) new Object[capacity]; |
| size = 0; |
| } |
| |
| public Array() { |
| this(10); |
| } |
| |
| public Array(E[] arr) { |
| data = Arrays.copyOf(arr, arr.length); |
| size = arr.length; |
| } |
| |
| public int getSize() { |
| return size; |
| } |
| |
| public int getCapacity() { |
| return data.length; |
| } |
| |
| public boolean isEmpty() { |
| return size == 0; |
| } |
| |
| |
| |
| |
| public void add(int index, E e) { |
| if (index < 0 || index > size) throw new RuntimeException("need 0 <= index <= size"); |
| if (size == data.length) resize(data.length * 2); |
| |
| System.arraycopy(data, index, data, index + 1, size - index); |
| data[index] = e; |
| size++; |
| } |
| |
| public void addFirst(E e) { |
| add(0, e); |
| } |
| |
| public void addLast(E e) { |
| add(size, e); |
| } |
| |
| |
| |
| |
| public E remove(int index) { |
| if (index < 0 || index >= size) throw new RuntimeException("need 0 <= index < size"); |
| |
| E ret = data[index]; |
| System.arraycopy(data, index + 1, data, index, size - index - 1); |
| size--; |
| data[size] = null; |
| |
| if (size == data.length / 4 && data.length / 2 != 0) resize(data.length / 2); |
| return ret; |
| } |
| |
| public E removeFirst() { |
| return remove(0); |
| } |
| |
| public E removeLast() { |
| return remove(size - 1); |
| } |
| |
| public void removeElement(E e) { |
| int index = find(e); |
| if (index != -1) remove(index); |
| } |
| |
| |
| |
| |
| public void set(int index, E e) { |
| if (index < 0 || index > size) throw new RuntimeException("need 0 <= index <= size"); |
| data[index] = e; |
| } |
| |
| |
| |
| |
| public E get(int index) { |
| if (index < 0 || index >= size) throw new RuntimeException("need 0 <= index < size"); |
| return data[index]; |
| } |
| |
| public E getFirst() { |
| return get(0); |
| } |
| |
| public E getLast() { |
| return get(size - 1); |
| } |
| |
| public boolean contains(E e) { |
| for (int i = 0; i < size; i++) { |
| if (data[i].equals(e)) return true; |
| } |
| return false; |
| } |
| |
| public int find(E e) { |
| for (int i = 0; i < size; i++) { |
| if (data[i].equals(e)) return i; |
| } |
| return -1; |
| } |
| |
| |
| |
| |
| private void resize(int newCapacity) { |
| E[] newData = (E[]) new Object[newCapacity]; |
| System.arraycopy(data, 0, newData, 0, size); |
| data = newData; |
| } |
| |
| public void swap(int a, int b) { |
| if (a < 0 || a >= size || b < 0 || b >= size) { |
| throw new IllegalArgumentException("Swap failed, require 0 <= index < size"); |
| } |
| E k = data[a]; |
| data[a] = data[b]; |
| data[b] = k; |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| sb.append(String.format("Array: size = %d, capacity = %d\n", size, data.length)); |
| sb.append('['); |
| for (int i = 0; i < size; i++) { |
| sb.append(data[i]); |
| if (i != size - 1) sb.append(", "); |
| } |
| sb.append(']'); |
| return sb.toString(); |
| } |
| } |
2、resize 复杂度分析

3、复杂度震荡

4、数组栈
| 很容易基于上面的动态数组来实现栈,并且 push、pop、peek 的复杂度都是 O(1) 级别的 |
| |
| |
| |
| public interface Stack<E> { |
| |
| void push(E e); |
| |
| E pop(); |
| |
| E peek(); |
| |
| int getSize(); |
| |
| boolean isEmpty(); |
| |
| } |
| public class ArrayStack<E> implements Stack<E> { |
| |
| private final Array<E> array; |
| |
| public ArrayStack() { |
| this.array = new Array<>(); |
| } |
| |
| public ArrayStack(int capacity) { |
| this.array = new Array<>(capacity); |
| } |
| |
| @Override |
| public void push(E e) { |
| array.addLast(e); |
| } |
| |
| @Override |
| public E pop() { |
| return array.removeLast(); |
| } |
| |
| @Override |
| public E peek() { |
| return array.getLast(); |
| } |
| |
| @Override |
| public int getSize() { |
| return array.getSize(); |
| } |
| |
| @Override |
| public boolean isEmpty() { |
| return array.isEmpty(); |
| } |
| |
| public int getCapacity() { |
| return array.getCapacity(); |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("ArrayStack: ["); |
| for (int i = 0; i < array.getSize(); i++) { |
| sb.append(array.get(i)); |
| if (i != array.getSize() - 1) sb.append(", "); |
| } |
| sb.append("] Top"); |
| return sb.toString(); |
| } |
| } |
5、数组队列
| 也很容易基于上面的动态数组来实现队列,enqueue 和 getFront 的复杂度都是 O(1) 级别的,但 dequeue 却是 O(n) |
| 或许可以优化,使得 dequeue 的复杂度也是 O(1) 级别的 |
| |
| |
| |
| public interface Queue<E> { |
| |
| void enqueue(E e); |
| |
| E dequeue(); |
| |
| E getFront(); |
| |
| int getSize(); |
| |
| boolean isEmpty(); |
| |
| } |
| public class ArrayQueue<E> implements Queue<E> { |
| |
| private final Array<E> array; |
| |
| public ArrayQueue() { |
| this.array = new Array<>(); |
| } |
| |
| public ArrayQueue(int capacity) { |
| this.array = new Array<>(capacity); |
| } |
| |
| @Override |
| public void enqueue(E e) { |
| array.addLast(e); |
| } |
| |
| @Override |
| public E dequeue() { |
| return array.removeFirst(); |
| } |
| |
| @Override |
| public E getFront() { |
| return array.getFirst(); |
| } |
| |
| @Override |
| public int getSize() { |
| return array.getSize(); |
| } |
| |
| @Override |
| public boolean isEmpty() { |
| return array.isEmpty(); |
| } |
| |
| public int getCapacity() { |
| return array.getCapacity(); |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("ArrayQueue: Front ["); |
| for (int i = 0; i < array.getSize(); i++) { |
| sb.append(array.get(i)); |
| if (i != array.getSize() - 1) sb.append(", "); |
| } |
| sb.append("] Tail"); |
| return sb.toString(); |
| } |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步