[數據結構] - 數組
阿新 • • 發佈:2019-01-14
throw 長度 空間 class a 否則 組類型 解決 exc index索引
1、Java數組介紹
在Java中,數組是用來存放同一種數據類型的集合,註意只能存放同一種數據類型(Object類型數組除外)。
在內存中,數組是一塊連續的區域。 拿上面的看電影來說,這幾個人在電影院必須坐在一起。
- 數組需要預留空間,在使用前要先申請占內存的大小,可能會浪費內存空間。 比如看電影時,為了保證10個人能坐在一起,必須提前訂好10個連續的位置。這樣的好處就是能保證10個人可以在一起。但是這樣的缺點是,如果來的人不夠10個,那麽剩下的位置就浪費了。如果臨時有多來了個人,那麽10個就不夠用了,這時可能需要將第11個位置上的人挪走,或者是他們11個人重新去找一個11連坐的位置,效率都很低。如果沒有找到符合要求的作為,那麽就沒法坐了。
- 插入數據和刪除數據效率低,插入數據時,這個位置後面的數據在內存中都要向後移。刪除數據時,這個數據後面的數據都要往前移動。 比如原來去了5個人,然後後來又去了一個人要坐在第三個位置上,那麽第三個到第五個都要往後移動一個位子,將第三個位置留給新來的人。 當這個人走了的時候,因為他們要連在一起的,所以他後面幾個人要往前移動一個位置,把這個空位補上。
- 隨機讀取效率很高。因為數組是連續的,知道每一個數據的內存地址,可以直接找到給地址的數據。
並且不利於擴展,數組定義的空間不夠時要重新定義數組。一種解決辦法是封裝一次數組,數組元素超過75%時候就動態擴容,新申請一個1.5倍的數組,把原來的數組全部拷貝過去。
①、數組的聲明
第一種方式:
數據類型 [] 數組名稱 = new 數據類型[數組長度];
這裏 [] 可以放在數組名稱的前面,也可以放在數組名稱的後面,我們推薦放在數組名稱的前面,這樣看上去 數據類型 [] 表示的很明顯是一個數組類型,而放在數組名稱後面,則不是那麽直觀。
第二種方式:
數據類型 [] 數組名稱 = {數組元素1,數組元素2,......}
這種方式聲明數組的同時直接給定了數組的元素,數組的大小由給定的數組元素個數決定。
//聲明數組1,聲明一個長度為3,只能存放int類型的數據 int [] myArray = new int[3]; //聲明數組2,聲明一個數組元素為 1,2,3的int類型數組 int [] myArray2 = {1,2,3};
②、訪問數組元素以及給數組元素賦值
數組是存在下標索引的,通過下標可以獲取指定位置的元素,數組小標是從0開始的,也就是說下標0對應的就是數組中第1個元素,可以很方便的對數組中的元素進行存取操作。
前面數組的聲明第二種方式,我們在聲明數組的同時,也進行了初始化賦值。
//聲明數組,聲明一個長度為3,只能存放int類型的數據
int [] myArray = new int[3];
//給myArray第一個元素賦值1
myArray[0] = 1;
//訪問myArray的第一個元素
System.out.println(myArray[0]);
上面的myArray 數組,我們只能賦值三個元素,也就是下標從0到2,如果你訪問 myArray[3] ,那麽會報數組下標越界異常。
③、數組遍歷
數組有個 length 屬性,是記錄數組的長度的,我們可以利用length屬性來遍歷數組。
//聲明數組2,聲明一個數組元素為 1,2,3的int類型數組
int [] myArray2 = {1,2,3};
for(int i = 0 ; i < myArray2.length ; i++){
System.out.println(myArray2[i]);
}
2、簡單封裝一個動態數組
package me.liangtian.array;
public class Array<E> {
/**
* 存放數據的數組
*/
private E[] data;
/**
* 數組中現有數據量
*/
private int size;
public Array(int capacity) {
data = (E[])new Object[capacity];
size = 0;
}
/**
* 默認數組長度10
*/
public Array() {
new Array<>(10);
}
/**
* 得到數組長度
*/
public int getCapacity() {
return data.length;
}
/**
* 已有數組大小
*/
public int getSize() {
return size;
}
/**
* 判斷數組是否為空
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 索引index處添加一個元素
* 1.判斷索引是否有效
* 2.判斷數組是否已經滿了,若滿了那麽擴容
* 3.從後往前,index處的元素後移一個位置
* 4.index索引處元素賦值
* 5.size++
*/
public void add(int index, E e) {
if(index < 0 || index > size) {
throw new IllegalArgumentException("add failed, index must between 0 and size");
}
if(index == size) {
resize( 2 * data.length);
}
for (int i = size -1; i >= index; i--) {
data[i+1] = data[i];
}
data[index] = e;
size++;
}
/**
* 在尾部添加新元素
*/
public void addLast(E e) {
add(size, e);
}
/**
* 在頭部添加新元素
*/
public void addFirst(E e) {
add(0, e);
}
/**
* 是否包含否個元素
*/
public boolean contains(E e) {
for (E e1 : data) {
if(e1.equals(e)) {
return true;
}
}
return false;
}
/**
* 動態擴容
* 1.新建一個容器,大小為指定大小newCapacity
* 2.將之前的容器的元素按原有順序放到新的容器中
* 3.將原指針指向新容器
*/
private void resize(int newCapacity) {
E[] newDate = (E[]) new Object[newCapacity];
for(int i = 0; i < size; i++) {
newDate[i] = data[i];
}
data = newDate;
}
/**
* 查找元素E在數組中的索引
* 1.遍歷所有的數組,若匹配到(equals非==)那麽返回索引,否則返回-1
*/
private int find(E e) {
for (int i = 0; i < data.length; i++) {
if(data[i].equals(e)) {
return i;
}
}
return -1;
}
/**
* 刪除元素並返回刪除之前的位置
* 若不存在則返回-1
*/
public int removeElement(E e) {
int index = find(e);
if(index != -1) {
remove(index);
}
return index;
}
/**
* 根據索引刪除元素,並返回刪除元素
* 1.判斷索引是否有效
* 2.將索引處的元素保存到單獨一個變量,用於返回
* 3.將所有元素左移,索引從小到大
* 4.將size索引處的元素清空,並且size-1
* 5.均攤算法復雜度。為防止算法復雜度振蕩,只有size <= data.leng/4 那麽重新調整數組大小為原大小二分之一
* 註意數組容器大小不能為0
*/
private E remove(int index) {
if(index < 0 || index >= size) {
throw new IllegalArgumentException("index must between 0 and size -1");
}
E removeData = data[index];
for(int i = index + 1; i < size; i++) {
data[i-1] = data[i];
}
data[index] = null;
size--;
if(size <= data.length/4 && data.length /2 != 0) {
resize(data.length /2);
}
return removeData;
}
}
[數據結構] - 數組