我们知道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 }