使用append之后数组维度消失_JAVA魅力之神奇的数组带给你不一样的乐趣
咱也不知道咋想的,周末的的時候閑來沒事,因為看到一道數(shù)組的面試題,我就跟數(shù)組杠上了,問題也不大,就是一個數(shù)組重寫的問題,我不知道大家有沒有遇到過類似的問題,在日常的開發(fā)環(huán)境中,反正我是沒遇到過,正常的開發(fā)就行,可能是因為我公司業(yè)務(wù)的原因吧,哈哈哈哈
但是,我個人的愛好就是會看一些面試題,去考察自己的知識點掌握情況,以及和市場的動態(tài),建議大家也可以這樣試一下,保持自己的競爭力,所以,在看到這道面試題之后,我就想去試一下,然后就有了下面的代碼詳解
看正式代碼之前,關(guān)注我給我點動力吧,讓我能更好的往下創(chuàng)作,嘿嘿嘿,好了,說正事
int類型數(shù)組
先來一個簡單的內(nèi)容,這個是正常的,以為我在日常的開發(fā)中有的時候還是能遇見的,哈哈哈哈,正不正常就以我是不是用過作為標(biāo)準(zhǔn)
public class Main {
public static void main(String[] args) {
Array score=new Array(10);
for(int i=0;i<8;i++){
score.addLast(i);
}
score.add(1,100);
score.addLast(99);
System.out.println(score.toString());
System.out.println(score.find(1));
System.out.println(score.contains(1));
System.out.println(score.remove(1));
System.out.println(score.toString());
System.out.println(score.removeElement(2));
System.out.println(score.toString());
}
}
修改為泛型
public class Array {
private T[] data;
private int size;
public Array() {
this(10);
}
public Array(int capacity) {
//java本身不支持直接new 一個泛型數(shù)組,所以用以下方法實現(xiàn)
data = (T[])new Object[capacity];
size = 0;
}
public int getSize() {
return size;
}
public int getCapacity() {
return data.length;
}
public boolean isEmpty() {
return size == 0;
}
/**
* 向數(shù)組末尾添加元素
*
* @param e
*/
public void addLast(T e) {
add(size, e);
}
/**
* 向數(shù)組開頭添加元素
*
* @param e
*/
public void addFirst(T e) {
add(0, e);
}
/**
* 向任意合法位置添加元素
*
* @param index
* @param e
*/
public void add(int index, T e) {
if (size == data.length) {
throw new IllegalArgumentException("Add is fail.Array is full");
}
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add is fail.Require index >= 0 and index < size");
}
for (int i = size; i > index; i--) {
data[i] = data[i - 1];
}
data[index] = e;
size++;
}
/**
* 獲取索引位置的元素
* 通過這種封裝,用戶無法查詢未使用的空間,保證了數(shù)據(jù)的安全性。
*
* @param index
* @return
*/
public T get(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Get is failed.Index is illegal");
}
return data[index];
}
/**
* 修改索引位置的元素
*
* @param index
* @param e
*/
public void set(int index, T e) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Set is failed.Index is illegal");
}
data[index] = e;
}
/**
* 數(shù)組中是否包含某個元素
*
* @param e
* @return
*/
public boolean contains(T e) {
for (int i = 0; i < size; i++) {
//注意值的比較應(yīng)修改為equals方法
if (data[i].equals(e)) {
return true;
}
}
return false;
}
/**
* 查詢數(shù)組中某個元素的索引
*
* @param e
* @return 沒有該元素則返回-1
*/
public int find(T e) {
for (int i = 0; i < size; i++) {
if (data[i].equals(e)) {
return i;
}
}
return -1;
}
/**
* 刪除index位置的元素,并且返回該元素
* 不用擔(dān)心刪除后原來size位置的元素,因為用無法訪問到它。
* 但是最好再寫一句data[size]=null 具體原因需要了解java的垃圾回收機(jī)制
*
* @param index
* @return
*/
public T remove(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Remove failed.Require index >=0 and index < size");
}
T ret = data[index];
for (int i = index; i < size - 1; i++) {
data[i] = data[i + 1];
}
//注意維護(hù)size
size--;
data[size]=null;
return ret;
}
/**
* 不用擔(dān)心數(shù)組為空的情況,因為數(shù)組如果為空,remove方法就會拋出異常
* @return
*/
public T removeFirst(){
return remove(0);
}
public T removeLast(){
return remove(size-1);
}
/**
* 從數(shù)組中刪除元素e
* @param e
*/
public boolean removeElement(T e){
int index=find(e);
if(index!=-1){
remove(index);
return true;
}else{
return false;
}
}
/**
* 重寫toString()方法
*
* @return
*/
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append(String.format("size= %d,capacity= %d", size, data.length));
res.append("[");
for (int i = 0; i < size; i++) {
res.append(data[i]);
if (i != size - 1) {
res.append(",");
}
}
res.append("]");
return res.toString();
}
}
那在添加之后,我們想的就是能不能動態(tài)添加呢
增加數(shù)組大小
前面當(dāng)我們向數(shù)組中添加元素時,如果index==size,表示數(shù)組已滿。
if (size == data.length) {
throw new IllegalArgumentException("Add is fail.Array is full");
}
現(xiàn)在可以考慮這樣做,依然判斷插入位置是否合法,但是當(dāng)size等于數(shù)組長度時,自動為數(shù)組擴(kuò)容——resize(2*data.length);
之所以是擴(kuò)為原來的2倍,是因為這樣擴(kuò)容量的大小和原來容量大小有關(guān),既不會過小也不會過大。
private void resize(int newCapacity){
T[] newData=(T[])new Object[newCapacity];
for(int i=0;i
newData[i]=data[i];
}
data=newData;
}
123456
減小數(shù)組大小
因為有了resize方法,實現(xiàn)起來就很簡單了。在remove(int index)方法中,移除一個元素且維護(hù)size后,再加上對維護(hù)后的size的判斷,如下。如果size已經(jīng)變?yōu)閏apacity的一半,則將數(shù)組容量減半。
if(size==data.length/2){
resize(data.length/2);
}
注意
resize()方法設(shè)為私有,是為了用戶只需使用這個數(shù)組類,不必去顧慮數(shù)組的大小。
時間復(fù)雜度的分析
通過對addLast(T[] e)和removeLast(T[] e)時間復(fù)雜度的分析,我們發(fā)現(xiàn)都是O(n)級別的。但是,這樣一般性地考慮最壞的情況在這種情景下是沒有太大意義的。因為addLast(T[] e)和removeLast(T[] e)操作并不會經(jīng)常觸發(fā)resize(int newCapcity)操作。所以用均攤復(fù)雜度分析的話,你會發(fā)現(xiàn)這兩個操作的均攤復(fù)雜度都是O(1)。因此resize(int newCapcity)這樣一個比較耗時的操作,如果保證不會每次都會觸發(fā),就可以將它的操作耗時分?jǐn)偟狡渌僮魃稀?/p>
現(xiàn)在再考慮另外一個場景,就是在addLast(T[] e)操作后,觸發(fā)了resize(int newCapcity),然后再removeLast(T[] e),又觸發(fā)了resize(int newCapcity);如此循環(huán)。像這樣addLast(T[] e)和removeLast(T[] e)的時間復(fù)雜度都是O(n)級別的,這就是所謂的復(fù)雜度的震蕩。以數(shù)組這個例子,之所以發(fā)生這種情況是因為我們在removeLast操作后,就接著進(jìn)行了resize操作這樣太著急了。那么該如何防止復(fù)雜度的震蕩呢?
可以這樣修改removeLast方法的代碼。
if(size==data.length/4 && data.length/4!=0){
resize(data.length/2);
}
加上data.length/4!=0的判斷是因為當(dāng)data.length/4==0的時候,數(shù)組長度變?yōu)?,這是不合法的。
修改后的完整代碼
public class Array {
private T[] data;
private int size;
public Array() {
this(10);
}
public Array(int capacity) {
//java本身不支持直接new 一個泛型數(shù)組,所以用以下方法實現(xiàn)
data = (T[])new Object[capacity];
size = 0;
}
public int getSize() {
return size;
}
public int getCapacity() {
return data.length;
}
public boolean isEmpty() {
return size == 0;
}
/**
* 向數(shù)組末尾添加元素
*
* @param e
*/
public void addLast(T e) {
add(size, e);
}
/**
* 向數(shù)組開頭添加元素
*
* @param e
*/
public void addFirst(T e) {
add(0, e);
}
/**
* 向任意合法位置添加元素
*
* @param index
* @param e
*/
public void add(int index, T e) {
/*if (size == data.length) {
throw new IllegalArgumentException("Add is fail.Array is full");
}*/
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add is fail.Require index >= 0 and index < size");
}
if(size == data.length){
resize(2*data.length);
}
for (int i = size; i > index; i--) {
data[i] = data[i - 1];
}
data[index] = e;
size++;
}
/**
* 獲取索引位置的元素
* 通過這種封裝,用戶無法查詢未使用的空間,保證了數(shù)據(jù)的安全性。
*
* @param index
* @return
*/
public T get(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Get is failed.Index is illegal");
}
return data[index];
}
/**
* 修改索引位置的元素
*
* @param index
* @param e
*/
public void set(int index, T e) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Set is failed.Index is illegal");
}
data[index] = e;
}
/**
* 數(shù)組中是否包含某個元素
*
* @param e
* @return
*/
public boolean contains(T e) {
for (int i = 0; i < size; i++) {
//注意值的比較應(yīng)修改為equals方法
if (data[i].equals(e)) {
return true;
}
}
return false;
}
/**
* 查詢數(shù)組中某個元素的索引
*
* @param e
* @return 沒有該元素則返回-1
*/
public int find(T e) {
for (int i = 0; i < size; i++) {
if (data[i].equals(e)) {
return i;
}
}
return -1;
}
/**
* 刪除index位置的元素,并且返回該元素
* 不用擔(dān)心刪除后原來size位置的元素,因為用無法訪問到它。
* 但是最好再寫一句data[size]=null 具體原因需要了解java的垃圾回收機(jī)制
*
* @param index
* @return
*/
public T remove(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Remove failed.Require index >=0 and index < size");
}
T ret = data[index];
for (int i = index; i < size - 1; i++) {
data[i] = data[i + 1];
}
//注意維護(hù)size
size--;
data[size]=null;
if(size==data.length/4 && data.length/4!=0){
resize(data.length/2);
}
return ret;
}
/**
* 不用擔(dān)心數(shù)組為空的情況,因為數(shù)組如果為空,remove方法就會拋出異常
* @return
*/
public T removeFirst(){
return remove(0);
}
public T removeLast(){
return remove(size-1);
}
/**
* 從數(shù)組中刪除元素e
* @param e
*/
public boolean removeElement(T e){
int index=find(e);
if(index!=-1){
remove(index);
return true;
}else{
return false;
}
}
/**
* 重寫toString()方法
*
* @return
*/
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append(String.format("size= %d,capacity= %d", size, data.length));
res.append("[");
for (int i = 0; i < size; i++) {
res.append(data[i]);
if (i != size - 1) {
res.append(",");
}
}
res.append("]");
return res.toString();
}
private void resize(int newCapacity){
T[] newData=(T[])new Object[newCapacity];
for(int i=0;i
newData[i]=data[i];
}
data=newData;
}
}
推薦
最后忍不住展示一下markdown寫作軟件的截圖,因為它實在是太美了。
- 好了,基本就整理了這一些,我不會說我就想到了這一些的,畢竟一個人的想法還是有限的,希望大家能夠在下面的評論區(qū)和我討論,大家一起學(xué)習(xí)成長,關(guān)注我,一個腦回路清奇的程序員
總結(jié)
以上是生活随笔為你收集整理的使用append之后数组维度消失_JAVA魅力之神奇的数组带给你不一样的乐趣的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 全局变量 内存不回收_JAVA
- 下一篇: jvm 参数_6个重要的JVM性能参数