數組基礎回顧
1、數組是一種常見的資料結構,用來存儲同一類型值的集合
2、數組就是存儲資料長度固定的容器,保證多個資料的資料類型要一緻
3、數組是一種順序存儲的線性表,所有元素的記憶體位址是連續的
4、例如:new 一個int基本類型的數組array
int[] array = new int[]{11,22,33};
5、數組的優勢與劣勢
數組具有很高的随機通路能力,通過數組下标就可以讀取對應的值
數組在插入與删除元素時,會導緻大量的元素移動
數組的長度是固定的,無法動态擴容,在實際開發中,我們更希望數組的容量是可以動态改變的
總結——數組适用于讀操作多,寫操作少的場景
自定義動态數組
動态數組的設計
protected int size;
private E[] elements;
圖示結構:
抽象父類接口設計
将動态數組與連結清單共同的屬性與方法抽取出,作為抽象類,提高複用性
抽象父類接口——List
public interface List {
//查無元素的傳回标志
int ELEMENT_NOT_FOUND = -1;
int size();
boolean isEmpty();
E set(int index, E element);
E get(int index);
boolean contains(E element);
int indexOf(E element);
void add(E element);
void add(int index, E element);
E remove(int index);
public E remove(E element);
void clear();
抽象父類設計
抽象父類AbstractList是對接口List的實作
public abstract class AbstractList implements List {
protected int size;
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public boolean contains(E element) {
return indexOf(element) != ELEMENT_NOT_FOUND;
}
public void add(E element) {
add(size, element);
}
protected void outOfBounds(int index) {
throw new IndexOutOfBoundsException("Index:" + index + ", Size:" + size);
}
protected void rangeCheck(int index) {
if (index < 0 || index >= size) {
outOfBounds(index);
}
}
protected void rangeCheckForAdd(int index) {
//index > size,元素可以添加在數組size位置,即數組尾部下一存儲單元
if (index < 0 || index > size) {
outOfBounds(index);
}
}
}
動态數組之DynamicArray
public class DynamicArray extends AbstractList {
private E[] elements;
//數組的預設初始化值
private static final int DEFAULT_CAPACITY = 10;
public DynamicArray(int capacity) {
//如果傳入的capacity>預設初始值,取capacity,否則取預設值
capacity = Math.max(capacity, DEFAULT_CAPACITY);
//通過new Object[],動态數組可以實作多對象化
elements = (E[]) new Object[capacity];
}
public DynamicArray() {
this(DEFAULT_CAPACITY);
}
public E set(int index,E element){
//檢查索引是否合法
rangeCheck(index);
//
E old = elements[index];
elements[index] = element;
return old;
}
public E get(int index){
rangeCheck(index);
return elements[index];
}
public int indexOf(E element){
//如果元素為空,單獨判斷,防止NPE
if (element == null){
for (int i = 0;i < size;i++){
if (elements[i] == null) return i;
}
}else {
//元素不為空
for (int i = 0;i < size;i++){
if (element.equals(elements[i])) return i;
}
}
//查無此元素
return ELEMENT_NOT_FOUND;
}
public void add(int index,E element){
//檢查索引是否合法
rangeCheckForAdd(index);
//檢查數組容量是否足夠
ensureCapacity(size + 1);
for (int i = size;i > index;i--){
elements[i] = elements[i - 1];
}
elements[index] = element;
size++;
}
public E remove(E element){
//調用indexOf擷取索引,通過索引删除指定元素
return remove(indexOf(element));
}
public E remove(int index){
//檢查索引是否合法
rangeCheck(index);
E old = elements[index];
for (int i = index + 1;i < size;i++){
elements[i - 1] = elements[i];
}
//将數組原來尾部最後的元素所在的位置置為null,釋放原來位址引用對應的對象記憶體
elements[--size] = null;
//檢測是否需要縮容
trim();
return old;
}
public void clear() {
for (int i = 0; i < size; i++) {
elements[i] = null;
}
size = 0;
}
private void ensureCapacity(int capacity){
int oldCapacity = elements.length;
//如果數組容量足夠,return
if (oldCapacity >= capacity) return;
//否則的話,數組擴容,數組擴容1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
E[] newElements = (E[]) new Object[newCapacity];
//将原有數組元素複制到新數組中
for (int i = 0;i < size;i++){
newElements[i] = elements[i];
}
//指向新數組
elements = newElements;
System.out.println(oldCapacity + "擴容為" + newCapacity);
}
@Override
public String toString() {
// size=3, [99, 88, 77]
StringBuilder string = new StringBuilder();
string.append("size=").append(size).append(", [");
for (int i = 0; i < size; i++) {
if (i != 0) {
string.append(", ");
}
string.append(elements[i]);
}
string.append("]");
return string.toString();
}
}
補充數組縮容
在每次删除數組元素時及清空數組時,進行縮容檢查
private void trim(){
int oldCapacity = elements.length;
int newCapacity = oldCapacity >> 1;
//如果元素的數量大于縮容後數組長度,或者小于初始量,不進行縮容操作
if (size >= (newCapacity) || size <= DEFAULT_CAPACITY) return;;
// 剩餘空間還很多
E[] newElements = (E[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
newElements[i] = elements[i];
}
elements = newElements;
System.out.println(oldCapacity + "縮容為" + newCapacity);
}
public void clear() {
// 數組清空,應該根據情況縮容,避免記憶體浪費
if (elements != null && elements.length > DEFAULT_CAPACITY) {
elements = (E[]) new Object[DEFAULT_CAPACITY];
}else {
for (int i = 0; i < size; i++) {
elements[i] = null;
}
}
size = 0;
}
全局的關系圖
聲明
個人能力有限,有不正确的地方,還請指正
文章為原創,歡迎轉載,注明出處即可
本文的代碼已上傳github,歡迎star