Java数据结构之数组

Java数据结构之数组

嗯,准备好好巩固一下自己的数据结构,第一站就是数组,这是一个很基础很基础的话题。不过还是要说一下,单纯的数组我也想不到有什么好说的,就看看ArryList吧。

Java中的ArrayList是我们经常用到的一个类,它内部就是利用数组来实现的。不知道你有没有研究过呢?其实并不复杂。看过来看过去,主要就是System.arraycopy();

Part1,初始化

ArraryList的初始化无它,你可以指定一个初始的容量也可以不指定,如果不指定的话,则默认初始化一个长度为0的Object数组。当然,你也可以利用另外一个集合来初始化ArrayLsit

public ArrayList(Collection collection) {
        if (collection == null) {
            throw new NullPointerException("collection == null");
        }

        Object[] a = collection.toArray();
        if (a.getClass() != Object[].class) {
            Object[] newArray = new Object[a.length];
            System.arraycopy(a, 0, newArray, 0, a.length);// copy。。。
            a = newArray;
        }
        array = a;
        size = a.length;
    }

Part2,CRUD

1.增。增加有两个方法,指定下标或不指定下标。我们直接看指定下标的方法。

@Override 
public void add(int index, E object) {
        Object[] a = array;//当前的数组
        int s = size;
        if (index > s || index < 0) {
            throwIndexOutOfBoundsException(index, s);
        }

        if (s < a.length) {// 从index开始的元素集体copy至index+1开始往后的位置
            System.arraycopy(a, index, a, index + 1, s - index);
        } else {
            // assert s == a.length;
            // 数组长度不够,就new一个新的数组
            Object[] newArray = new Object[newCapacity(s)];
            //将0至(index-1)位置的元素拷贝至新数组
            System.arraycopy(a, 0, newArray, 0, index);
            //将index开始往后的元素拷贝至新数组
            System.arraycopy(a, index, newArray, index + 1, s - index);
            array = a = newArray;// 指向新数组
        }
        a[index] = object;//指定位置元素赋值
        size = s + 1;
        modCount++;// 编辑次数,很少用到
    }

// 扩容规则 MIN_CAPACITY_INCREMENT = 12。返回新数组的长度
private static int newCapacity(int currentCapacity) {
        int increment = (currentCapacity < (MIN_CAPACITY_INCREMENT / 2) ?
                MIN_CAPACITY_INCREMENT : currentCapacity >> 1);
        return currentCapacity + increment;
    }

当然,还有一个addAll(int index, Collection collection)方法,相当于把新集合的元素依次添加至指定位置。和上面原理相似,不多说了。

2.删。删也有两种,一个是指定下标,另一个是指定元素。来看下~

@Override 
public E remove(int index) {
        Object[] a = array;
        int s = size;
        if (index >= s) {
            throwIndexOutOfBoundsException(index, s);
        }
        // 不神秘,拿到指定index的元素,让最后返回
        @SuppressWarnings("unchecked") E result = (E) a[index];
        // 将index+1开始往后的元素拷贝至index开始的位置。注意 --s
        System.arraycopy(a, index + 1, a, index, --s - index);
        a[s] = null;  // Prevent memory leak。末尾元素置null,防止内存泄漏
        size = s;
        modCount++;
        return result;
    }

@Override 
public boolean remove(Object object) {
  // 这个原理同上,不过要注意只会删除该元素第一次出现的位置。返回值:是否成功删除
        Object[] a = array;
        int s = size;
        if (object != null) {
            for (int i = 0; i < s; i++) {
                if (object.equals(a[i])) {
                    System.arraycopy(a, i + 1, a, i, --s - i);
                    a[s] = null;  // Prevent memory leak
                    size = s;
                    modCount++;
                    return true;
                }
            }
        } else {
            for (int i = 0; i < s; i++) {
                if (a[i] == null) {
                    System.arraycopy(a, i + 1, a, i, --s - i);
                    a[s] = null;  // Prevent memory leak
                    size = s;
                    modCount++;
                    return true;
                }
            }
        }
        return false;
    }

删除里,还有一个clear(),这个就是直接将所有元素置null,size置0。

3.剩下的改和查就没什么要说的了。遍历数组,想必都会。

Part3,扩展SparseArray

SparseArrayArrayList都是利用数组来实现的,不过SparseArray是以键值对的形式存储数据的,类似于Map

SparseArray中维护了两个数组,一个keys,一个values。

通过看源码发现,SparseArray内部keys的存储是排序过的,CRUD的时候是通过二分查找,先找到key对应的index,然后就能找到对应index的value,所以效率会稍微高一些。需要注意的是,它的删除并不会将该位置元素置null,而是放置一个常量Obj对象。其余的实现原理无非也是copy来copy去。不多说了。有兴趣的大家可以自己看下源码。

哦哦,有一个有意思的地方,就是gc()。因为它删除的时候,并不直接置null,所以有个垃圾回收。

private void gc() {
        // Log.e("SparseArray", "gc start with " + mSize);

        int n = mSize;
        int o = 0;
        int[] keys = mKeys;
        Object[] values = mValues;

        for (int i = 0; i < n; i++) {
            Object val = values[i];
            // DELETED 就是那个常量Obj对象
            if (val != DELETED) {
                if (i != o) {
                    keys[o] = keys[i];
                    values[o] = val;
                    values[i] = null;
                }

                o++;
            }
        }

        mGarbage = false;// 是否还有垃圾
        mSize = o;

        // Log.e("SparseArray", "gc end with " + mSize);
    }

Part4,小结

关于数组,目前能想到的就这么多了。很基础,一定要烂熟。

你可能感兴趣的:(Java)