資料結構筆記整理和思考--動態陣列和靜態陣列的領悟

eBusinessMan發表於2015-03-15

最近在複習資料結構,但再次重溫線性結構中的連續儲存章節時,通過使用C語言來模擬Java中的ArrayList的各個方法,感覺對Java中的ArrayList的體會有深刻了。遂想趁此機會將陣列的知識點整理一下。

首先要了解:陣列分為靜態陣列和動態陣列(後者是前者的升級版,其實就是將靜態陣列通過一個類來再封裝一次而已,沒什麼神祕的)。

一.靜態陣列

靜態陣列又有預設建立,靜態建立和動態建立,共三種建立方式;

A.     預設建立:所有的元素的初始值都是0

                     int[] i=new int[5];

B.     靜態建立:建立陣列時(開闢每個元素的記憶體空間時)就賦自定義值了

          int[] I = {1,2,3};

C.     動態建立:在預設建立的基礎上,後面根據實際情況再針對每個元素賦值

             int[] i=new int[5];

             i[0]=4; i[1]=3;……..

二.動態陣列(ArrayList)

                  裡面封裝了一個Object陣列。

                  相對於靜態陣列的優點:

1.      可以動態的新增和刪除元素;add(obj) remove(obj);

2.      可以動態的改變陣列的容量;

                                   構造器三個:

                                  A.     預設的構造器,將會以預設(16)的大小來初始化內部的陣列
                                                    public ArrayList();

                                  B.     用一個ICollection物件來構造,並將該集合的元素新增到ArrayList
                                                    public ArrayList(ICollection);
                                  C.     用指定的大小來初始化內部的陣列  
                                                    public ArrayList(int);

                                           !!!

                                                    Note:

                                                    初始化ArrayList時指定的大小是指容量,而不是其有效元素的個數,

                                                    而其size()方法返回的是其有效元素的個數。

                                          !!!

                                           重要的兩個屬性:CountCapacity

                                           Count :是隻讀屬性,指有效元素的個數:size()方法返回的就是它!!

                                           Capacity : 可以設定,但是一定要>= Count

                                   兩個重要卻少用的方法:

                               trimToSize():當我們可以確定動態陣列不會再add入元素時,應該在適當時機呼叫此方法將陣列中的Capacity減少到等於Count,就是說:釋放掉(Capacity-Count)           個元素的空間。這是優化方面的細節!!

                               toArray() : 可以轉化為Object[]  是把ArrayList的元素Copy到一個新的陣列中。

 

三.使用注意點(效率方面)

1.      自動拆裝箱:

我們知道ArrayList中其實是封裝了一個Object[] , 所以存在著:當我們將值型別的資料add進去時,會出現自動拆裝箱的操作,這會在編譯階段拖低點效率了。可是對於物件引用型別就不會了。(其實都不差什麼。)

2.      陣列擴容:

這是一定注意的!!!!

程式不斷地add入元素,當Count = Capacity 時,ArrayList物件會自動建立一個2*CapacityObject[]空間(就是new Object[2*Capacity]),然後將原來的陣列元素copy到新的Objec陣列中,再丟棄原來的Object陣列。

是不是很費時間?是不是很極大的拖低了效率?!!!

因此,我們在編碼階段,就應該有個大概的估算,儘量在建立動態陣列時定義好合適的初始大小。

在網上有兩個很好的案例:

(1)     ArrayList  list = new ArrayList();//預設16個元素空間

for( int i =0 ; i<200 ; i++ ){

    list.add(new String(“**”));    

}

剖析:程式執行完了後,list的屬性Capacity == 16*2*2*2*2 ;就是說陣列擴容了4次!!這不止,最後還多了56=16*2*2*2*2 – 200)個空閒元素空間浪費!!

(2)     預計有30個元素而建立了一個ArrayList

ArrayList List = new ArrayList(30);

在執行過程中,加入了31個元素,那麼陣列會擴充到60個元素的大小,而這時候不會有新的元素再增加進來,而且有沒有呼叫TrimSize方法,那麼就有1次擴容的操作,並且浪費了29個元素大小的空間。如果這時候,用:

ArrayList List = new ArrayList(40);

那麼一切都解決了。

所以說,正確的預估可能的元素,並且在適當的時候呼叫TrimSize方法是提高ArrayList使用效率的重要途徑。

3.      頻繁的呼叫IndexOfContains等方法(SortBinarySearch等方法經過優化,不在此列)引起的效率損失!!!

首先,我們要明確一點,ArrayList是動態陣列,它不包括通過Key或者Value快速訪問的演算法,所以實際上呼叫IndexOfContains等方法是執行的簡單的迴圈來查詢元素,所以頻繁的呼叫此類方法並不比你自己寫迴圈並且稍作優化來的快,如果有這方面的要求,建議使用Hashtable或SortedList等鍵值對的集合。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29900383/viewspace-1460774/,如需轉載,請註明出處,否則將追究法律責任。

相關文章