Preface
The last article described the basic knowledge of data structure and linked list, address: (1) Link List of Android Data Structure Learning and Algorithms This is the second article in a series on arrays.
Summary
Use of arrays
Arrays are implemented in java as follows:
String[] arr1 = new String[3];// Create an array of size 3
arr1[0] = "0";
arr1[1] = "1";
arr1[2] = "2";
String[] arr2 = new String[]{"0", "1", "2"};// Create a data size of 3 and assign values
I believe you all understand the above code, but in actual development, there are not many places to use arrays like this. We use arrays like ArrayList more often. In fact, it is more appropriate to use containers to describe ArrayList. We maintain an array inside him. We can easily add, delete and modify an ArrayList because containers already provide a lot of methods. It's great for us to use it without our own maintenance.
Characteristics of arrays
Arrays are allocated in a continuous data space, so the size of the array must be determined when allocating space to them. Like the two ways we declare the array above, we determine the size. But the list is different, it is a dynamic space, can change the length at will, so the initialization does not need to determine the size.
Advantage:
- The efficiency of accessing and locating elements is very high.
Disadvantages:
- Because space is fixed, inserting and deleting elements is inefficient.
Array List Array Container
ArrayList we use a lot, there are many methods are very useful, we use these methods to understand arrays and array containers, forming the idea of data structure
Construction method
transient Object[] elementData;
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
Here is an elementData, which is an array. The transient modifier is used to describe serialization related. We don't care here. This array is created when we initialize ArrayList. The container is used to maintain this array for our convenience.
Let's look at another constructor whose parameters are the initialization size of the array:
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
}
Another way to construct this is to copy the contents of another array into a new array. Here is an Arrays.copyOf() method. Arrays is a class specially designed for manipulating arrays. It provides a large number of methods to call the underlying c, which we will not go deep into, and it will be difficult to extract when we drill in.
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
add series methods
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
A total of 2 lines of code, the second line is a simple array assignment operation, adding new elements to elementData and adding the size of the array to 1. Remember that the size of the array I mentioned earlier is fixed at initialization. If an array of size 1, how can we add a second element to it? So we can think of the first line. The ensureCapacityInternational method must have used some way to increase the size of the original array, so let's go in and see:
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
This code first determines whether the content of elementData is empty, and if so, sets a minimum capacity for the array, which is the maximum of the default size (10) and the current size of the array + 1. After determining this size, all that remains is to expand the array. Let's continue to see:
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
If the new capacity of the array is larger than the current size of the array, the group method name is also in place.
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
Here we also revise the size of the primary capacity. When the number of elements in the array is small, about a single digit, the capacity will increase to 10. When there are more elements, like more than 20, the capacity will increase by 1.5 times. The last line uses the method in Array. The same way is to copy the elements of the array.
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
This add method inserts elements into the specified position. First of all, it expands the array, because if you want to insert elements at a certain position in an array, assuming that this position is in the middle of the array, then it means that the element at + 1 position in the middle of the array moves backwards to the last element, but we know that the array does not have this function, so System A is still used. The rraycopy method replicates arrays, which is actually the underlying method of Arrays.copy().
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
src represents the data source, srcPos represents the location of replication, dest represents the result data source to be replicated, destPos represents the replication location of the result data source, and length represents the replication length. After substitution, the element from index to size - index is copied from elementData, then the replacement position starts from index + 1, the length of the element is size - index, and finally the location of index is assigned. Look at the picture:
After looking at the above two add methods, the process of the addAll method is the same. The first step is to expand, and the second step is to copy the array. We won't go into details.
get method
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];
}
The get method is just that... So array query elements are simple, aren't they?
remove method
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
Most of the methods and contents here seem to be very similar. See the picture, not to mention much:
Then, the removal (Object o) process is similar. Interested friends can understand it if they go to have a look at it for themselves.
summary
Having gone through a series of methods in ArrayList, we can summarize the following:
1. The element efficiency of query array is very high.
2. Inserting and deleting elements in arrays requires copying elements in arrays, which is inefficient.
3. As a container, ArrayList dynamically maintains the size and content of arrays. We just need to care about how to use them.
4. Arrays has a large number of methods for manipulating arrays
5. The above content of the article is more to let you understand arrays and array containers rather than source code, I hope you can get some results.