數組
-
初始容量
-
添加元素
- 按index添加
- 末尾添加
- 起始位置添加
-
刪除元素
- 末尾刪除
- 索引刪除
- 起始刪除
-
查找
-
包含
-
擴容
簡單時間複雜度分析
均攤時間複雜度
複雜度震盪
代碼
package array;
/**
* 動態數組
* <p>
* 思想: 新建一個新的數組,容量需要進行擴大,
* 然後讓成員變量數組指針指向新建的數組,原來的數組
* 沒有指針指向,會被Java 垃圾回收器回收
* <p>
* 時間複雜度分析:
* 增: O(n)
* 刪: O(n)
* 改: 已知索引O(1),未知索引:O(n)
* 查:已知索引O(1),未知索引:O(n)
* <p>
* 添加操作: 均攤時間複雜度
* <p>
* 複雜度震盪: capacity = n
* addLast 擴容 之後緊接着 removeLast 兩次時間複雜度 O(n)
* removeLast
* 原因: removeLast 時resize() 過於着急
* 解決方案:Lazy 縮容時候 當size == capacity/4 纔將capacity減半 空間換時間
*/
public class DynamicArray<E> {
private E[] data;
private int size;
/**
* @param capacity 傳數組的容量
*/
public DynamicArray(int capacity) {
data = (E[]) new Object[capacity];
size = 0;
}
public DynamicArray() {
this(10);
}
/**
* @return 數組長度
*/
public int getSize() {
return size;
}
/**
* @return 當前數組容量
*/
public int getCapacity() {
return data.length;
}
/**
* @return 是否爲空
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 均攤時間複雜度
* O(1)
*
* @param e 向所有元素後添加一個新元素
*/
public void addLast(E e) {
add(size, e);
}
/**
* @param e 向所有元素第一個添加一個新元素 O(n)
*/
public void addFirst(E e) {
add(0, e);
}
/**
* 指定位置添加元素
* <p>
* 時間複雜度,index取值的概率是一樣的
* 每個元素期望是多少,平均時間度O(n/2) ~~ O(n),
* 時間複雜度 :
* 需要按照最壞的方案計算,
* 考慮最好的意義不大
*
* @param index 指定位置
* @param e 元素
*/
public void add(int index, E e) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add Failed");
}
if (size == data.length) {
resize(2 * data.length);
}
//每一個元素向後一個位置
for (int i = size - 1; i >= index; i--) {
data[i + 1] = data[i];
}
data[index] = e;
size++;
}
/**
* 數組擴容 :
* 思想,數組當前長度或大或小,不理想,最好是倍數
* <p>
* ArrayList 擴容是原來Size的1.5倍數
* <p>
* 時間複雜度:O(n)
* <p>
* 均攤時間複雜度: 假設capacity = 8, 並且每一次添加操作都是用addLast,
* 9次addLast 操作,觸發一次resize,總共進行了17次基本操作,平均每次addLast
* 就執行2次基本操作(擴容倍數),
* 假設capacity = n,n+1次addLast,觸發resize,總共進行2n+1次基本操作
* 平均每次addLast就執行2次基本操作(擴容倍數),
*
* @param newCapacity 新數組長度
*/
private void resize(int newCapacity) {
E[] newData = (E[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
data = newData;
}
/**
* 刪除一個
*
* @param e 刪除元素
*/
public void removeElement(E e) {
int index = find(e);
if (index != -1) {
remove(index);
}
}
/**
* 時間複雜度:O(n)
*
* @return
*/
public E removeFirst() {
return remove(0);
}
/**
* 均攤時間複雜度
* O(1)
*
* @return
*/
public E removeLast() {
return remove(size);
}
/**
* 時間複雜度:O(n)
*
* @param index 刪除索引元素
*/
public E remove(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Remove Failed");
}
E ret = data[index];
for (int i = index + 1; i < size; i++) {
data[i - 1] = data[i];
}
size--;
data[size] = null;
if (size == data.length / 4 && data.length / 2 != 0) {
resize(data.length / 2);
}
return ret;
}
/**
* 時間複雜度:O(1): 支持隨機索引
*
* @param index 索引
* @param e 索引對應元素
*/
public void set(int index, E e) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Set Failed");
}
data[index] = e;
}
/**
* @param index 索引
* @return 索引對應元素
*/
public E get(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Get Failed");
}
return data[index];
}
/**
* 時間複雜度:O(n)
*
* @return 是否包含
*/
public boolean contains(E e) {
for (int i = 0; i < size; i++) {
if (e.equals(data[i])) {
return true;
}
}
return false;
}
/**
* 時間複雜度:O(n)
*
* @return 元素的索引
*/
public int find(E e) {
for (int i = 0; i < size; i++) {
if (e.equals(data[i])) {
return i;
}
}
return -1;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(String.format("Array:Size = %d , capacity = %d \n", size, data.length));
builder.append("[");
for (int i = 0; i < size; i++) {
builder.append(data[i]);
if (i != size - 1) {
builder.append(", ");
}
}
builder.append("]");
return builder.toString();
}
}