正確使用ArrayList和LinkedList

原文連接地址
java

        最近在看數據結構,發現這個東西不錯,記錄下來,以便分享!        
           ArrayList內部是使用可増長數組實現的,因此是用get和set方法是花費常數時間的,可是若是插入元素和刪除元素,除非插入和刪除的位置都在表末尾,不然代碼開銷會很大,由於裏面須要數組的移動。
           LinkedList是使用雙鏈表實現的,因此get會很是消耗資源,除非位置離頭部很近。可是插入和刪除元素花費常數時間。
           咱們來看下面一個例子:
           public void listTest1(List<Integer> list, int n) {
                   list.clear();
           for (int i=0; i<n; i++) {
            list.add(i);
          }
           }
          上面這個例子,不管是ArrayList仍是LinkedList運行的時間都是O(N),由於每次的操做都是在表末尾進行的。若是咱們把add方法換成下面的呢!
           list.add(0, i);
           該完以後,對於LinkedList運行時間是O(N),可是對於ArrayList則是O(N^2),一位每次添加都須要移動數組,運行時間是O(N)
        再看看下面的這個例子:計算list中數據之和
        public int listSum(List<Integer> list) {
        int sum = 0;
        for (int i=0; i<list.size(); i++) {
            sum += list.get(i);
        }
        return sum;
    }
       這個例子對於ArrayList運行時間是O(N),可是對於LinkedList運行時間就是O(N^2),可是若是咱們使用加強for循環,那麼就會不同。代碼以下:
       public int listSum2(List<Integer> list) {
        int sum = 0;
        for (Integer i: list) {
            sum += i;
        }
        return sum;
    }
       這樣不管是ArrayList和LinkedList其運行時間都是O(N),由於迭代器會有效的從一項到下一項推動。
       下面咱們說一個remove方法
        問題:將一個表中的全部偶數項所有刪除,要求不能建立新表。
       最簡單的就是,進行for遍歷,而後取出數值判斷是不是偶數,若是是就刪除,代碼以下:
       public static void removeEvensOne(List<Integer> list) {
        for (int i=0; i<list.size(); i++) {
            if (list.get(i) % 2 == 0) {
                list.remove(i); //移除的是i位置上的元素
            }
        }
    }
       咱們來分析一下,若是傳入的參數是Arraylist,那麼效率必定會很低,我作了一下測試,建立一個400000項的ArrayList,程序運行時間大約是16s。想着若是傳入的是LinkedList是否會很快,答案是否!對於LinkedList運行時間至少要一分多鐘,這就奇怪了LinkedList不是刪除操做是常數時間嗎。咱們仔細看看這裏面需最消耗時間的是list.get(i)和list.remove(i),首先對於LinkedList的get()操做時間複雜度是O(N),對於remove(i)時間,LinkedList須要到達位置i,那麼如何到達,只能是從第一個元素一直搜索下去,其時間複雜讀也是O(N),因此對於這個程序LinkedList消耗的時間要比ArrayList多的多。
     既然用for循環須要.get(i),那咱們使用加強for循環好了,代碼以下:
     public static void removeEvensThree(List<Integer> list) {
        for (Integer i: list) {
            if (i%2 == 0) {
                list.remove(i); //移除的是元素i
            }
        }
     }
     運行一下,拋出異常java.util.ConcurrentModificationException。也就是說list.remove()破壞了加強for循環,這個方法不行,可是它給了咱們一個思路:在迭代器找到一個偶數時,咱們可使用迭代器來刪除這個偶數值。咱們使用Iterator迭代器,代碼以下:
     public static void removeEvensTwo(List<Integer> list) {
        Iterator<Integer> it = list.iterator();
        while (it.hasNext()) {
            if (it.next() % 2 == 0) {
                it.remove();
            }
        }
    }
       這個代碼中咱們不須要查找,仍是使用400000個元素的list進行測試,ArrayList沒有什麼變化,時間依然是16s,這是由於即便迭代器位於要刪除的節點上,刪除以後元素仍是要移動。對於LinkedList花費的時間小於1s。
        從上面咱們能夠看出:ArrayList雖然get和set快,可是remove卻很慢。對於LinkedList雖然刪除和插入很快,可是若是期間使用了get那麼同樣會很慢。若是是有大量的刪除操做咱們仍是使用Iterator迭代器比較好。數組

      原文地址http://www.exceptionhelp.com
數據結構

相關文章
相關標籤/搜索