Thinker

            - long way to go...

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            24 隨筆 :: 0 文章 :: 143 評論 :: 0 Trackbacks
              我們知道ArrayList是基于Array的,所以它擁有Array的優點,適用于按索引取值的場合,但是它不適合插入數據和刪除數據,因為每插入或刪除一次就會產生一次大量數組內容Copy的操作。而LinkedList正好與ArrayList相反,它比較適合與插入刪除操作,不適合于索引取值,因為它不可以像數組一樣根據索引值直接就可以定位元素的地址,而需要從頭至尾一個一個的來數位置。
              那么有沒有一種數據結構既擁有數據索引取值快速的特性,又擁有快速刪除元素的優點呢?當然有,下面我介紹的就是其中的一種方式,我稱之為無序數組(概念可能與數組的概念有些沖突,因為數組本身是有序的),這種數組包裝方法是基于數組的,所以擁有數組快速索引取值的特點;并且在刪除元素的時候并不移動(Copy)數組內部元素,所以刪除元素的時候速度很快。缺點就是損失了數組的有序性,同時因為該數組是無序的,所以沒有必要提供數據中間插入操作,只可以向數據的末尾添加數據。
              這個數據結構的設計是基于效率的,所以它只適合于對數組的按索引取值和隨機刪除元素的效率要求都比較高,同時對數組的有序性(這里的有序性不是指數組元素的排序順序,而是指數組元素的索引順序)沒有任何要求的場合。
               這個數據結構的一個使用示例場合就是隨機取數據。可以用該數組存儲數據源,然后隨機生成一個索引,并將該索引對應的元素remove掉。而且還能保證數據不被重復讀取。
              下面提供的示例代碼抽取了這個數組的最基本功能,很清晰,沒有什么需要解釋的地方。導致數組無序和快速刪除的根源就在于 remove(int index) 方法中,大家自己看吧。
            1 public class NoOrderArray
            2 {
            3   private Object[] values = null;
            4 
            5   private int size = 0;
            6 
            7   /**
            8    * 數組 NoOrderArray 的構造函數。 <br>
            9    * 
           10    * @param capacity int - 數組的初始容量。
           11    */
           12   public NoOrderArray(int capacity)
           13   {
           14     if (capacity < 0)
           15       throw new IllegalArgumentException("Illegal Capacity: " + capacity);
           16 
           17     values = new Object[capacity];
           18   }
           19 
           20   /**
           21    * 數組 NoOrderArray 的構造函數,初始容量為 8.<br>
           22    */
           23   public NoOrderArray()
           24   {
           25     this(10);
           26   }
           27 
           28   /**
           29    * 設定數組的容量大小,使其至少滿足 minCapacity 所指的大小。 <br>
           30    * 
           31    * @param minCapacity int - 新的容量值。
           32    */
           33   public void ensureCapacity(int minCapacity)
           34   {
           35     int oldCapacity = values.length;
           36 
           37     if (minCapacity > oldCapacity)
           38     {
           39       Object[] oldValues = values;
           40 
           41       int newCapacity = (oldCapacity * 3/ 2 + 1;
           42 
           43       if (newCapacity < minCapacity)
           44         newCapacity = minCapacity;
           45 
           46       values = new Object[newCapacity];
           47 
           48       System.arraycopy(oldValues, 0, values, 0, size);
           49     }
           50   }
           51 
           52   /**
           53    * 向數組 NoOrderArray 中添加元素內容。 <br>
           54    * 
           55    * @param value - 添加的內容。
           56    */
           57   public void add(Object value)
           58   {
           59     ensureCapacity(size + 1);
           60 
           61     values[size] = value;
           62 
           63     size ++;
           64   }
           65 
           66   /**
           67    * 清除數組 NoOrderArray 中的全部元素。 <br>
           68    */
           69   public void clear()
           70   {
           71     // 釋放內存
           72     for (int i = 0; i < size; i ++)
           73       values[i] = null;
           74 
           75     size = 0;
           76   }
           77 
           78   /**
           79    * 返回數組 NoOrderArray 中指定索引的元素。 <br>
           80    * 
           81    * @param index int - 索引值。
           82    * 
           83    * @return Object - 對應的元素。
           84    */
           85   public Object get(int index)
           86   {
           87     if (index >= size || index < 0)
           88       throw new IndexOutOfBoundsException("Index out of bounds.");
           89 
           90     return values[index];
           91   }
           92 
           93   /**
           94    * 判斷當前 NoOrderArray 數組是否為空。 <br>
           95    * 
           96    * @return boolean - 如果為空返回 <code>true</code>.
           97    */
           98   public boolean isEmpty()
           99   {
          100     return (size == 0);
          101   }
          102 
          103   /**
          104    * 移除 NoOrderArray 數組中指定位置的元素。 <br>
          105    * 
          106    * @param index int - 索引值。
          107    * 
          108    * @return Object - 被移除的元素。
          109    */
          110   public Object remove(int index)
          111   {
          112     if (index >= size || index < 0)
          113       throw new IndexOutOfBoundsException("Index out of bounds.");
          114 
          115     Object value = values[index];
          116 
          117     if (index != size - 1)
          118     {
          119       // 將數組最后一個值補充到被移除的位置。
          120       values[index] = values[size - 1];
          121     }
          122     values[size - 1] = null; // 防止該位置永久持有對象的引用
          123     size --;
          124 
          125     return value;
          126   }
          127 
          128   /**
          129    * 判斷指定的數據是否在 NoOrderArray 數組中。 <br>
          130    * 
          131    * @param value Object - 需要判斷的數據。
          132    * 
          133    * @return boolean - 如果包含返回 <code>true</code>.
          134    */
          135   public boolean contains(Object value)
          136   {
          137     if (value == null)
          138     {
          139       for (int i = 0; i < size; i ++)
          140         if (values[i] == null)
          141           return true;
          142     }
          143     else
          144     {
          145       for (int i = 0; i < size; i ++)
          146         if (value.equals(values[i]))
          147           return true;
          148     }
          149 
          150     return false;
          151   }
          152 
          153   /**
          154    * 返回當前數組的大小。 <br>
          155    * 
          156    * @return int - 當前數組的大小。
          157    */
          158   public int size()
          159   {
          160     return size;
          161   }
          162 
          163   /*
          164    * (non-Javadoc)
          165    * 
          166    * @see java.lang.Object#toString()
          167    */
          168   public String toString()
          169   {
          170     StringBuffer buffer = new StringBuffer();
          171 
          172     buffer.append('[');
          173 
          174     for (int index = 0; index < size; index ++)
          175     {
          176       Object value = values[index];
          177 
          178       if (index > 0)
          179         buffer.append(',');
          180 
          181       buffer.append(value);
          182     }
          183 
          184     buffer.append(']');
          185 
          186     return buffer.toString();
          187   }
          188 
          189   /**
          190    * @param args
          191    */
          192   public static void main(String[] args)
          193   {
          194     // TODO 自動生成方法存根
          195   }
          196 }


          posted on 2007-08-27 17:18 Long 閱讀(2974) 評論(9)  編輯  收藏 所屬分類: Java

          評論

          # re: 快速隨機訪問和可刪除的數組 2007-08-28 00:21 姜利陽
          不錯!  回復  更多評論
            

          # re: 快速隨機訪問和可刪除的數組 2007-08-28 10:22 dennis
          這個東西不僅僅是無序這樣的缺點,在大規模數據remove的時候將占據大量無效的內存,因為remove方法僅僅將value[size-1]賦給value[index],然后size--,可沒有將value[size-1]設置為null,這個值盡管已經不用且不可訪問,但是將一直占據在內存里直到整個數組被棄用。修改下remove方法:
          public Object remove(int index) {
          if (index >= size || index < 0)
          throw new IndexOutOfBoundsException("Index out of bounds.");

          Object value = values[index];

          if (index != size - 1) {
          // 將數組最后一個值補充到被移除的位置。
          values[index] = values[size - 1];
          values[size - 1] = null; //設置為null
          }

          size--;

          return value;
          }  回復  更多評論
            

          # re: 快速隨機訪問和可刪除的數組 2007-08-28 10:22 dennis
          況且,我認為這個需求一般用哈希表更好點。  回復  更多評論
            

          # re: 快速隨機訪問和可刪除的數組 2007-08-28 10:35 Long
          @dennis
          樓上朋友,
          我曾經考慮過將values[size - 1] = null;但是沒有考慮周全。當時只考慮到values[size - 1] 的值被先前Remove掉的那個元素位置引用,所以沒有必要設置為null。忽視了這個值可能再次被Remove掉而數組仍然持有引用。
          謝謝提醒。

          另外,哈希表的確是一個好東東,不過對于一個頻繁使用的、數據元素超多、哈希值分布不均勻的應用時,太浪費內存空間了。

          問題已修正。
            回復  更多評論
            

          # re: 快速隨機訪問和可刪除的數組 2007-08-30 12:46 JAVA面試題
          同意  回復  更多評論
            

          # re: 快速隨機訪問和可刪除的數組 2009-03-16 12:55 sun java 工程師
          不是吧,你的這些操作,ArrayList接口已經幫你全都弄好了。為什么自己再弄一個。

          你說的對,ArrayList插入或刪除一次數據就會產生一次大量數組內容Copy的操作。確實是這樣。

          可是單獨增加一個值,并沒有進行那么復雜的操作,具體請看ArrayList.add(E e)這個方法。

          你的上面的代碼的實現,在ArrayList中已經都有了。好好研究ArrayList吧。
          另外說一點你上面的代碼 remove(int index),你的這個方法已經實現了,但是改變了數組的順序,憑什么把最后一個數據插入到index這個位置。理論上都是順移順序的。  回復  更多評論
            

          # re: 快速隨機訪問和可刪除的數組 2009-03-16 13:00 xx
          @sun java 工程師
          注意是快速隨機訪問和快速可刪除。
          ArrayList無法做到快速可刪除。  回復  更多評論
            

          # re: 快速隨機訪問和可刪除的數組 2009-03-16 13:06 sun java 工程師
          @Long
          if (index != size - 1) { //如果相等怎么辦???
          // 將數組最后一個值補充到被移除的位置。
          values[index] = values[size - 1];
          values[size - 1] = null; //設置為null
          }
          size--;
          可否改成一下代碼
          if (index != size - 1) {
          // 將數組最后一個值補充到被移除的位置。
          values[index] = values[size - 1];
          }
          values[size - 1] = null; //設置為null
          size--;  回復  更多評論
            

          # re: 快速隨機訪問和可刪除的數組 2009-03-16 13:14 sun java 工程師
          @xx
          O(∩_∩)O哈哈~,看來都在看這邊文章,如果不考慮順序的話,按照上面的思路下來,本人建議繼承ArrayList再寫一個方法就OK了
          如:
          public class MyList<E> extends ArrayList<E>{
          public Ojbect removeValue(int index){
          if (index >= size || index < 0)
          throw new IndexOutOfBoundsException("Index out of bounds.");
          Object value = values[index];
          if (index != size - 1) {
          // 將數組最后一個值補充到被移除的位置。
          values[index] = values[size - 1];
          }
          values[size - 1] = null; //設置為null
          size--;
          return value
          }
          }  回復  更多評論
            

          # re: 快速隨機訪問和可刪除的數組 2009-03-16 13:19 Long
          @sun java 工程師
          老兄說的是,
          代碼已修正。

          呵呵,寫這個類的時候沒有繼承自ArrayList的主要原因是為了保持它的接口的簡單性,因為ArrayList的接口中有很多與Array的順序/序號操作的相關,比如add(int,object)等等。  回復  更多評論
            

          主站蜘蛛池模板: 伊春市| 绥德县| 青铜峡市| 皋兰县| 崇左市| 阿城市| 景东| 滨州市| 四川省| 包头市| 南漳县| 洛扎县| 安塞县| 五大连池市| 余江县| 肥东县| 运城市| 喀喇沁旗| 方山县| 靖远县| 恭城| 江达县| 定远县| 喀喇沁旗| 香港 | 奎屯市| 天台县| 大兴区| 噶尔县| 荆州市| 苗栗市| 云浮市| 凉城县| 武隆县| 阳城县| 崇阳县| 浦北县| 蕲春县| 白山市| 景洪市| 石景山区|