常用数据结构-线性表及Java 动态数组 深究

【Java心得总结六】Java容器中——Collection在前面自己总结的一篇博文中对Collection的框架结构做了整理,这里深究一下Java中list的实现方式

1.动态数组

In computer science, a dynamic arraygrowable arrayresizable arraydynamic tablemutable 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^

 

posted @ 2015-04-23 14:39  xlturing  阅读(897)  评论(0编辑  收藏  举报