常用数据结构-线性表及Java 动态数组 深究
【Java心得总结六】Java容器中——Collection在前面自己总结的一篇博文中对Collection的框架结构做了整理,这里深究一下Java中list的实现方式
1.动态数组
In computer science, a dynamic array, growable array, resizable array, dynamic table, mutable array, or array list is a random access, variable-size list data structure that allows elements to be added or removed. It is supplied with standard libraries in many modern mainstream programming languages.
A dynamic array is not the same thing as a dynamically allocated array, which is a fixed-size arraywhose size is fixed when the array is allocated, although a dynamic array may use such a fixed-size array as a back end.
——维基百科
我们可以看出动态数组在动态分配数组(固定大小数组)的基础上实现的可随机存取大小可变的一种数据结构
2.Java中ArrayList实现
我截取了部分ArrayList的Java实现:
代码段1
1 public class ArrayList<E> extends AbstractList<E> 2 implements List<E>, RandomAccess, Cloneable, java.io.Serializable 3 { 4 private transient Object[] elementData; 5 6 private int size; 7 8 public ArrayList(int initialCapacity) { 9 super(); 10 if (initialCapacity < 0) 11 throw new IllegalArgumentException("Illegal Capacity: "+ 12 initialCapacity); 13 this.elementData = new Object[initialCapacity]; 14 } 15 16 public ArrayList() { 17 this(10); 18 } 19 20 public ArrayList(Collection<? extends E> c) { 21 elementData = c.toArray(); 22 size = elementData.length; 23 // c.toArray might (incorrectly) not return Object[] (see 6260652) 24 if (elementData.getClass() != Object[].class) 25 elementData = Arrays.copyOf(elementData, size, Object[].class); 26 } 27 28 private void grow(int minCapacity) { 29 // overflow-conscious code 30 int oldCapacity = elementData.length; 31 int newCapacity = oldCapacity + (oldCapacity >> 1); 32 if (newCapacity - minCapacity < 0) 33 newCapacity = minCapacity; 34 if (newCapacity - MAX_ARRAY_SIZE > 0) 35 newCapacity = hugeCapacity(minCapacity); 36 // minCapacity is usually close to size, so this is a win: 37 elementData = Arrays.copyOf(elementData, newCapacity); 38 } 39 40 private static int hugeCapacity(int minCapacity) { 41 if (minCapacity < 0) // overflow 42 throw new OutOfMemoryError(); 43 return (minCapacity > MAX_ARRAY_SIZE) ? 44 Integer.MAX_VALUE : 45 MAX_ARRAY_SIZE; 46 } 47 48 /* 增加元素 */ 49 public boolean add(E e) { 50 ensureCapacityInternal(size + 1); // Increments modCount!! 51 elementData[size++] = e; 52 return true; 53 } 54 55 public void add(int index, E element) { 56 rangeCheckForAdd(index); 57 58 ensureCapacityInternal(size + 1); // Increments modCount!! 59 System.arraycopy(elementData, index, elementData, index + 1, 60 size - index); 61 elementData[index] = element; 62 size++; 63 } 64 65 private void rangeCheckForAdd(int index) { 66 if (index > size || index < 0) 67 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); 68 } 69 70 /* 删除元素 */ 71 public E remove(int index) { 72 rangeCheck(index); 73 74 modCount++; 75 E oldValue = elementData(index); 76 77 int numMoved = size - index - 1; 78 if (numMoved > 0) 79 System.arraycopy(elementData, index+1, elementData, index, 80 numMoved); 81 elementData[--size] = null; // Let gc do its work 82 83 return oldValue; 84 } 85 86 public boolean remove(Object o) { 87 if (o == null) { 88 for (int index = 0; index < size; index++) 89 if (elementData[index] == null) { 90 fastRemove(index); 91 return true; 92 } 93 } else { 94 for (int index = 0; index < size; index++) 95 if (o.equals(elementData[index])) { 96 fastRemove(index); 97 return true; 98 } 99 } 100 return false; 101 } 102 103 private void fastRemove(int index) { 104 modCount++; 105 int numMoved = size - index - 1; 106 if (numMoved > 0) 107 System.arraycopy(elementData, index+1, elementData, index, 108 numMoved); 109 elementData[--size] = null; // Let gc do its work 110 } 111 112 /* 查找元素 */ 113 public E get(int index) { 114 rangeCheck(index); 115 116 return elementData(index); 117 } 118 119 public int indexOf(Object o) { 120 if (o == null) { 121 for (int i = 0; i < size; i++) 122 if (elementData[i]==null) 123 return i; 124 } else { 125 for (int i = 0; i < size; i++) 126 if (o.equals(elementData[i])) 127 return i; 128 } 129 return -1; 130 } 131 132 public boolean contains(Object o) { 133 return indexOf(o) >= 0; 134 } 135 136 private void rangeCheck(int index) { 137 if (index >= size) 138 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); 139 } 140 141 /* 修改元素 */ 142 public E set(int index, E element) { 143 rangeCheck(index); 144 145 E oldValue = elementData(index); 146 elementData[index] = element; 147 return oldValue; 148 } 149 }
代码段2
1 public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { 2 T[] copy = ((Object)newType == (Object)Object[].class) 3 ? (T[]) new Object[newLength] 4 : (T[]) Array.newInstance(newType.getComponentType(), newLength); 5 System.arraycopy(original, 0, copy, 0, 6 Math.min(original.length, newLength)); 7 return copy; 8 }
- 代码4行,可以看出Java利用了一个Object数组来支持动态数组ArrayList的存取,Object[]的初始大小可以利用构造函数来进行设置
- 在代码28行,可以看出当Object数组不够用的时候,Java会利用grow函数对原有数组进行扩展。查看Java Arrays类会找到copyOf静态方法,会发现Java会新开辟一段更大的存储空间(newLength),然后再将原有数组的数据全部复制到新的数组中,并返回新的引用。之后grow会将elementData指向新的数组。
- 而接下来我按照增删查改的顺序对Java中的函数进行了列举,基本就是普通的动态数组操作,就不一一说明。
3.Java中LinkedList实现
Java中LinkedList就是用双向链表来实现的,我截取了部分代码:
代码段1:
1 public class LinkedList<E> 2 extends AbstractSequentialList<E> 3 implements List<E>, Deque<E>, Cloneable, java.io.Serializable 4 { 5 transient int size = 0; 6 7 transient Node<E> first; 8 9 transient Node<E> last; 10 11 public LinkedList() { 12 } 13 14 public LinkedList(Collection<? extends E> c) { 15 this(); 16 addAll(c); 17 } 18 /* 链表基本操作 */ 19 private void linkFirst(E e) { 20 final Node<E> f = first; 21 final Node<E> newNode = new Node<>(null, e, f); 22 first = newNode; 23 if (f == null) 24 last = newNode; 25 else 26 f.prev = newNode; 27 size++; 28 modCount++; 29 } 30 31 void linkLast(E e) { 32 final Node<E> l = last; 33 final Node<E> newNode = new Node<>(l, e, null); 34 last = newNode; 35 if (l == null) 36 first = newNode; 37 else 38 l.next = newNode; 39 size++; 40 modCount++; 41 } 42 43 void linkBefore(E e, Node<E> succ) { 44 // assert succ != null; 45 final Node<E> pred = succ.prev; 46 final Node<E> newNode = new Node<>(pred, e, succ); 47 succ.prev = newNode; 48 if (pred == null) 49 first = newNode; 50 else 51 pred.next = newNode; 52 size++; 53 modCount++; 54 } 55 56 private E unlinkFirst(Node<E> f) { 57 // assert f == first && f != null; 58 final E element = f.item; 59 final Node<E> next = f.next; 60 f.item = null; 61 f.next = null; // help GC 62 first = next; 63 if (next == null) 64 last = null; 65 else 66 next.prev = null; 67 size--; 68 modCount++; 69 return element; 70 } 71 72 private E unlinkLast(Node<E> l) { 73 // assert l == last && l != null; 74 final E element = l.item; 75 final Node<E> prev = l.prev; 76 l.item = null; 77 l.prev = null; // help GC 78 last = prev; 79 if (prev == null) 80 first = null; 81 else 82 prev.next = null; 83 size--; 84 modCount++; 85 return element; 86 } 87 88 E unlink(Node<E> x) { 89 // assert x != null; 90 final E element = x.item; 91 final Node<E> next = x.next; 92 final Node<E> prev = x.prev; 93 94 if (prev == null) { 95 first = next; 96 } else { 97 prev.next = next; 98 x.prev = null; 99 } 100 101 if (next == null) { 102 last = prev; 103 } else { 104 next.prev = prev; 105 x.next = null; 106 } 107 108 x.item = null; 109 size--; 110 modCount++; 111 return element; 112 } 113 114 /* 查找操作 */ 115 public int indexOf(Object o) { 116 int index = 0; 117 if (o == null) { 118 for (Node<E> x = first; x != null; x = x.next) { 119 if (x.item == null) 120 return index; 121 index++; 122 } 123 } else { 124 for (Node<E> x = first; x != null; x = x.next) { 125 if (o.equals(x.item)) 126 return index; 127 index++; 128 } 129 } 130 return -1; 131 } 132 133 public int lastIndexOf(Object o) { 134 int index = size; 135 if (o == null) { 136 for (Node<E> x = last; x != null; x = x.prev) { 137 index--; 138 if (x.item == null) 139 return index; 140 } 141 } else { 142 for (Node<E> x = last; x != null; x = x.prev) { 143 index--; 144 if (o.equals(x.item)) 145 return index; 146 } 147 } 148 return -1; 149 } 150 151 /*添加操作*/ 152 public boolean addAll(int index, Collection<? extends E> c) { 153 checkPositionIndex(index); 154 155 Object[] a = c.toArray(); 156 int numNew = a.length; 157 if (numNew == 0) 158 return false; 159 160 Node<E> pred, succ; 161 if (index == size) { 162 succ = null; 163 pred = last; 164 } else { 165 succ = node(index); 166 pred = succ.prev; 167 } 168 169 for (Object o : a) { 170 @SuppressWarnings("unchecked") E e = (E) o; 171 Node<E> newNode = new Node<>(pred, e, null); 172 if (pred == null) 173 first = newNode; 174 else 175 pred.next = newNode; 176 pred = newNode; 177 } 178 179 if (succ == null) { 180 last = pred; 181 } else { 182 pred.next = succ; 183 succ.prev = pred; 184 } 185 186 size += numNew; 187 modCount++; 188 return true; 189 } 190 191 public boolean add(E e) { 192 linkLast(e); 193 return true; 194 } 195 196 /* 删除操作 */ 197 public E removeFirst() { 198 final Node<E> f = first; 199 if (f == null) 200 throw new NoSuchElementException(); 201 return unlinkFirst(f); 202 } 203 204 public E removeLast() { 205 final Node<E> l = last; 206 if (l == null) 207 throw new NoSuchElementException(); 208 return unlinkLast(l); 209 } 210 211 /* 修改操作 */ 212 public E set(int index, E element) { 213 checkElementIndex(index); 214 Node<E> x = node(index); 215 E oldVal = x.item; 216 x.item = element; 217 return oldVal; 218 } 219 }
代码段2:
1 private static class Node<E> { 2 E item; 3 Node<E> next; 4 Node<E> prev; 5 6 Node(Node<E> prev, E element, Node<E> next) { 7 this.item = element; 8 this.next = next; 9 this.prev = prev; 10 } 11 }
- 代码段1的7行和9行,我们可以看到Java中LinkedList的实现就是我们所熟知的双向链表数据结构,并且声明了头指针和尾指针分别指向链表的头和尾
- 每个节点的结构见代码段2,发现是基本的双向链表节点结构
- 而从代码18行开始就是常规的链表操作,包括插入结点和删除结点的操作
- 而之后的增删查改操作大都是利用基本的链表操作实现的
- 另外,值得注意的是LinkedList在Java中还有一个特殊功效就是通过向上转型当做队列Queue来使用
如下面这段代码
Queue<Integer> queue = new LinkedList<Integer>();
这里向上转型无非是将LinkedList限制为头尾读取。
Java中的动态数组实现,比较简单,复习回顾下,做下记录^v^