####前言 今天就要離校了,大學生涯也走到了盡頭。確定有不少不捨,不捨的是學校的安逸和美麗的女朋友。同時也對本身的將來充滿着信心,但願本身可以強大起來,保護本身想要保護的人。以前一段時間,在掘金上面看到一篇文章,文章提到了一個思想:學會編程,而不是學會Java,文中提到了自定義一個模仿ArrayList的類,要去實現其中的add,get,remove等方法。同時正好我以前也在看《Java數據結構和算法》這本書,文中第二章也詳細講解了數組,因此本身也動手完成了自定義一個數組內和動態數組類,因而乎就有了這篇文章去溫故而知新。程序員
####數組 數組是應用最普遍的數組存儲結構。 優勢:插入快,若是知道下標,能夠很是地存取 缺點:查找慢,刪除慢,大小固定。算法
####動態數組 Java也提供了順序結構的動態數組類ArrayList,數組採用的是順序結構來存儲數據,能夠有效利用空間,可用於存儲大量的數據,數組不適合動態的改變它所存儲的數據,如增長,刪除一個單元等。因爲數組採用順序結構存儲數據,數組得到第n單元中的數據的速度要比鏈表得到第n單元中的數據快。編程
####寫一個數組類 這個數組類確定有insert(),find(),delete(),display()這些基礎方法。 insert():插入一個元素,而後數組長度+1,返回true。數組
public void insert(long value){
a[count]=value;
count++;
}
複製代碼
find():根據元素的值,遍歷整個數組的元素,找到返回true,沒有找到返回falsebash
public boolean find(long searchValue){
int j;
for(j=0;j<count;j++){
if(a[j]==searchValue){
break;
}
}
if(j==count){
return false;
}else{
return true;
}
}
複製代碼
delete():根據元素的值,遍歷整個數組的元素,沒有找到對應的元素值,返回flase, 找到了該元素存儲在數組的位置,讓該位置後面的全部元素向前移動一個位置,返回true。數據結構
public boolean delete(long deleteValue){
int j;
for(j=0;j<count;j++){
if(a[j]==deleteValue){
break;
}
}
if(j==count){
return false;
}else{
for(int k=j;k<count;k++){
a[k]=a[k+1];
}
count--;
return true;
}
}
複製代碼
display():遍歷整個數組的元素,打印數組。app
public void display(){
int j;
for(j=0;j<count;j++){
System.out.print(a[j]+" ");
}
System.out.print("\n");
}
複製代碼
####寫一個簡單的動態數組類 其實這仍是比較難的,可是看了一下ArrayList的源碼後,寫一個帶有基本功能的類仍是沒有問題的。基本方法:add(),remove(),contain(),toString(),toArray(),removeRange(),get()等。數據結構和算法
首先是構造器,有2個構造器,分別一個是有參和無參的。有參的構造器須要傳入的參數是所需初始化數組的容量大小,若是這個容量大小>0,那麼建立一個數組,數組容量大小爲傳入的參數。若是這個容量大小=0,那麼把EMPTY_ELEMENTDATA
這個空數組對象賦給elementData
這個數組變量。若是這個容器大小<0,那麼拋出參數異常。對於無參構造器而言,直接把elementData
數組變量引用這個DEFAULT_CAPACITY_ELEMENTDATA
數組對象。ide
public CmazList1(int inititalCapcacity){
if(inititalCapcacity>0){
this.elementData=new Object[inititalCapcacity];
}else if(inititalCapcacity==0){
this.elementData=EMPTY_ELEMENTDATA;
}else{
throw new IllegalArgumentException("參數錯誤");
}
}
public CmazList1(){
this.elementData=DEFAULT_CAPACITY_ELEMENTDATA;
}
複製代碼
**contain():**調用indexOf()方法,若是indexOf返回的int值大於0就說明此對象在數組中找到對應存儲的位置,那麼返回true,不然返回false。ui
public boolean contain(Object object){
return indexOf(object)>=0;
}
複製代碼
**indexOf():**經過遍歷整個數組元素,判斷該數組的某個單元是否包含這個對象,若是找到了這個對象,返回其存儲在數組的下標,不然返回-1。
public int indexOf(Object object){
if(object==null){
for(int i=0;i<size;i++){
if(elementData[i]==null){
return i;
}
}
}else{
for(int i=0;i<size;i++){
if(elementData[i].equals(object)){
return i;
}
}
}
return -1;
}
複製代碼
add():先調用 ensureCapacityInternal()方法,進行相關擴容等處理操做。而後添加元素,size加1。size用於記錄在數組中元素的個數。
public boolean add(Object object){
ensureCapacityInternal(size+1);
elementData[size++]=object;
return true;
}
複製代碼
ensureCapacityInternal():首先看整個英文的意思是確保內部容量。首先要判斷這個數組是哪個構造器初始化的。若是這個數組是無參構造器初始化的,那麼這個數組確定沒有設置初始化數組的容量大小,是一個空數組。而後把minCapacity
的值在傳入的minCapacity
的值和默認容器大小的值中取出最大的一個值,即爲minCapacity
的值。而後調用ensureExplicitCapacity()
。
private void ensureCapacityInternal(int minCapacity){
if(this.elementData==DEFAULT_CAPACITY_ELEMENTDATA){
minCapacity=Math.max(minCapacity, DEFAULT_CAPACITY);
}
ensureExplicitCapacity(minCapacity);
}
複製代碼
ensureExplicitCapacity():這個方法進行的操做,去判斷是否要進行擴容。若是minCapacity大於數組的長度,說明這個數組須要進行擴容了,由於數組的空間容不下即將添加的元素。接下來調用grow()去進行擴容。
private void ensureExplicitCapacity(int minCapacity){
modCount++;
if(minCapacity-elementData.length>0){
grow(minCapacity);
}
}
複製代碼
**grow():進行擴容的操做,擴容後的大小是原來大小的1.5倍。>>1是右移1位,移動後的值是移動前的值的0.5倍。若是擴容後的大小比minCapacity
**小,那麼就把minCapacity
的值賦給newCapacity
。若是newCapacity的值比咱們以前定義的MAX_ARRAY_SIZE
還要大的話,那麼就調用hugeCapacity()
方法。MAX_ARRAY_SIZE咱們定義的大小是Integer.MAX_VALUE-8,也就是Integer型數值的最大值-8。補充:**原碼是直接將一個數值換算成二進制數,但計算機以補碼的形式保存全部的整數。**通常狀況下,不會出現newCapacity>MAX_ARRAY_SIZE
的狀況。
private void grow(int minCapacity){
int oldCapacity=elementData.length;
int newCapacity=oldCapacity+(oldCapacity>>1);
if(minCapacity-newCapacity>0){
newCapacity=minCapacity;
}
if(newCapacity-MAX_ARRAY_SIZE>0){
newCapacity=hugeCapacity(minCapacity);
}
this.elementData=Arrays.copyOf(elementData,newCapacity);
}
複製代碼
**remove():**遍歷整個數組元素,若是發現該數組包含這個對象,那麼調用fastRemove()刪除存儲此對象的單元。
public boolean remove(Object object){
if(object==null){
for(int i=0;i<size;i++){
if(elementData[i]==null){
fastRemove(i);
return true;
}
}
}else{
for(int i=0;i<size;i++){
if(elementData[i].equals(object)){
fastRemove(i);
return true;
}
}
}
return false;
}
複製代碼
**remove():**首先調用get()方法,經過下標獲得此單元存儲的元素值。這個方法返回就是這個元素值。計算出刪除此元素須要挪動的元素個數。若是挪動的元素個數>0,那麼調用System.arraycopy()方法,獲得一個移動後的數組。elementData[--size]=null
,移動後的數組剩餘一個存儲沒有任何元素的單元,那麼size--,把沒有存儲任何元素的單元置爲null,通知GC清除無用的內存。 講解:System.arraycopy(src, srcPos, dest, destPos, length) src:源數組 srcPos:源數組要複製元素的起始位置 dest:目的數組 destPos:目的數組把複製的元素放置的起始位置 length:複製元素的長度
public E remove(int index){
rangeCheck(index);
modCount++;
E oldValue=get(index);
int movedNum=size-1-index;
if(movedNum>0){
System.arraycopy(elementData,index+1, elementData, index, movedNum);
}
elementData[--size]=null;
return oldValue;
}
複製代碼
removeRange():須要注意的是toIndex指的是要刪除的最後一個元素的下一個元素的下標。思路和remove()是同樣的,只是remove()是刪除一個元素,removeRange()刪除的是多個元素。
public void removeRange(int fromIndex,int toIndex){
modCount++;
// int movedNum=size-1-(toIndex-1);
int movedNum=size-toIndex;
if(movedNum>0){
System.arraycopy(elementData, toIndex, elementData, fromIndex, movedNum);
}
int newSize=size+fromIndex-toIndex;
for(int i=newSize;i<size;i++){
elementData[newSize]=null;
}
size=newSize;
}
複製代碼
源碼附上
public class CmazList1<E> {
private static final Object[] DEFAULT_CAPACITY_ELEMENTDATA={};
private static final Object[] EMPTY_ELEMENTDATA={};
private static final int MAX_ARRAY_SIZE=Integer.MAX_VALUE-8;
private static int DEFAULT_CAPACITY=10;
private Object[] elementData;
private int modCount=0;
private int size;
public CmazList1(int inititalCapcacity){
if(inititalCapcacity>0){
this.elementData=new Object[inititalCapcacity];
}else if(inititalCapcacity==0){
this.elementData=EMPTY_ELEMENTDATA;
}else{
throw new IllegalArgumentException("參數錯誤");
}
}
public CmazList1(){
this.elementData=DEFAULT_CAPACITY_ELEMENTDATA;
}
public boolean contain(Object object){
return indexOf(object)>=0;
}
public int indexOf(Object object){
if(object==null){
for(int i=0;i<size;i++){
if(elementData[i]==null){
return i;
}
}
}else{
for(int i=0;i<size;i++){
if(elementData[i].equals(object)){
return i;
}
}
}
return -1;
}
public boolean add(Object object){
ensureCapacityInternal(size+1);
elementData[size++]=object;
return true;
}
private void ensureCapacityInternal(int minCapacity){
if(this.elementData==DEFAULT_CAPACITY_ELEMENTDATA){
minCapacity=Math.max(minCapacity, DEFAULT_CAPACITY);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity){
modCount++;
if(minCapacity-elementData.length>0){
grow(minCapacity);
}
}
private void grow(int minCapacity){
int oldCapacity=elementData.length;
int newCapacity=oldCapacity+(oldCapacity>>1);
if(minCapacity-newCapacity>0){
newCapacity=minCapacity;
}
if(newCapacity-MAX_ARRAY_SIZE>0){
newCapacity=hugeCapacity(minCapacity);
}
this.elementData=Arrays.copyOf(elementData,newCapacity);
}
private int hugeCapacity(int minCapacity){
if(minCapacity<0){
throw new OutOfMemoryError();
}
return minCapacity>MAX_ARRAY_SIZE?Integer.MAX_VALUE:MAX_ARRAY_SIZE;
}
public boolean remove(Object object){
if(object==null){
for(int i=0;i<size;i++){
if(elementData[i]==null){
fastRemove(i);
return true;
}
}
}else{
for(int i=0;i<size;i++){
if(elementData[i].equals(object)){
fastRemove(i);
return true;
}
}
}
return false;
}
private void fastRemove(int index){
modCount++;
int movedNum=size-1-index;
if(movedNum>0){
System.arraycopy(elementData, index+1, elementData, index, movedNum);
}
elementData[--size]=null;
}
public E remove(int index){
rangeCheck(index);
modCount++;
E oldValue=get(index);
int movedNum=size-1-index;
if(movedNum>0){
System.arraycopy(elementData,index+1, elementData, index, movedNum);
}
elementData[--size]=null;
return oldValue;
}
public E get(int index){
rangeCheck(index);
return (E) elementData[index];
}
@Override
public String toString() {
// TODO Auto-generated method stub
StringBuilder sb=new StringBuilder();
for(int i=0;i<size;i++){
sb.append(elementData[i]+" ");
}
return sb.toString();
}
public Object[] toArray(){
return Arrays.copyOf(this.elementData, size);
}
/**
* toIndex是指要刪除的最後一個元素的下一個元素的下標
* 好比我要刪除下標爲5的元素,那麼toIndex=6
* @param fromIndex
* @param toIndex
*/
public void removeRange(int fromIndex,int toIndex){
modCount++;
// int movedNum=size-1-(toIndex-1);
int movedNum=size-toIndex;
if(movedNum>0){
System.arraycopy(elementData, toIndex, elementData, fromIndex, movedNum);
}
//
int newSize=size+fromIndex-toIndex;
for(int i=newSize;i<size;i++){
elementData[newSize]=null;
}
size=newSize;
}
private void rangeCheck(int index){
if(index>=size||index<0){
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
}
private String outOfBoundsMsg(int index){
return "index:"+index+",size="+size;
}
}
複製代碼
####尾言 數據結構和算法的複利性遠比其餘時髦技術要多的多。對於程序員來講,不進則死。 打好牢固的基礎,必定是沒有錯的。笨鳥先飛,很適合我。