1. 程式人生 > >JDK,常見數據結構解讀

JDK,常見數據結構解讀

父親 vat com except get 圖片 on() parent 容量

一。情有獨鐘

  對數據結構情有獨鐘,打算慢慢把jdk裏的實現都讀一遍,發現其中的亮點,持續更新。

二。ArrayList

  這應該是我們學習java最早接觸的到的數據結構,眾所周知,數組在申請了內存之後,無法擴展;而數組隊列,是實現了動態擴容的功能,意義上是為動態數組,實際上的數組擴容是不允許在原地址上伸長的,很簡單,因為在你申請的數組空間之後,可能存在別的被申請掉的內存;要實現動態數組,必然是新申請一個更大的連續內存空間,並替換到原來的引用中。

技術分享圖片

  從構造函數,可以清楚看到,elementData,就是這個存儲數據的內存地址。

技術分享圖片

  然後,找到添加的接口,add;在真正賦值之前,會進行grow方法。

技術分享圖片

  技術分享圖片

  可以看到,真正幹活的是這個copyof,找到最後,就是這個方法。

  首先這個泛型數組,會先判斷一下如果是Object父類,則直接new Object,如果不是則調用Arrays的接口創建,才去新建一個數組,然後就會去拷貝數組到新的數組,並返回這個被拷貝的數組。

    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        @SuppressWarnings("unchecked")
        T[] copy 
= ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }

  它的get方法,簡單判斷一下是否大於元素容量,防止內存泄漏的操作。

    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

  它的remove方法,是將這個位置之後的所有元素,前移一個位置,並將最後的元素設置為null。

    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;
    }

  它提供的排序接口,設計的是傳入一個比較器,可以自定升序還是降序,最終一個分支使用的是mergeSort。最後還校驗了一下modcount,前後是否相等,如果不相等拋出並發異常,有點CAS的思想。

    @Override
    @SuppressWarnings("unchecked")
    public void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

  

    public static void sort(Object[] a) {
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a);
        else
            ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
    }

  長度小於7插入排序,反正是個n平方的排序,

    private static void mergeSort(Object[] src,
                                  Object[] dest,
                                  int low,
                                  int high,
                                  int off) {
        int length = high - low;

        // Insertion sort on smallest arrays
        if (length < INSERTIONSORT_THRESHOLD) {
            for (int i=low; i<high; i++)
                for (int j=i; j>low &&
                         ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
                    swap(dest, j, j-1);
            return;
        }

        // Recursively sort halves of dest into src
        int destLow  = low;
        int destHigh = high;
        low  += off;
        high += off;
        int mid = (low + high) >>> 1;
        mergeSort(dest, src, low, mid, -off);
        mergeSort(dest, src, mid, high, -off);

        // If list is already sorted, just copy from src to dest.  This is an
        // optimization that results in faster sorts for nearly ordered lists.
        if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
            System.arraycopy(src, low, dest, destLow, length);
            return;
        }

        // Merge sorted halves (now in src) into dest
        for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
            if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
                dest[i] = src[p++];
            else
                dest[i] = src[q++];
        }
    }

三。PriorityQueue

  優先隊列,讀作優先寫作二叉樹,也叫堆(大頂堆,小頂堆)。

  它的實現方法是數組,使用數組做二叉樹,每個元素e[i]的孩子為e[2*i+1],e[2*i+2]。

技術分享圖片

  找到添加元素的方法;比較器為空的時候;它從末尾插入,先找出父親,如果父節點比自己大,則繼續往上,將父節點往下移動,直到找到比它小的位置插入,默認是一個小頂堆。

    public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        modCount++;
        int i = size;
        if (i >= queue.length)
            grow(i + 1);
        size = i + 1;
        if (i == 0)
            queue[0] = e;
        else
            siftUp(i, e);
        return true;
    }

    private void siftUpComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>) x;
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (key.compareTo((E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = key;
    }

  彈出操作就是把堆定元素拿走,然後不斷往下找合適的往上移。

    public E poll() {
        if (size == 0)
            return null;
        int s = --size;
        modCount++;
        E result = (E) queue[0];
        E x = (E) queue[s];
        queue[s] = null;
        if (s != 0)
            siftDown(0, x);
        return result;
    }
    private void siftDownComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>)x;
        int half = size >>> 1;        // loop while a non-leaf
        while (k < half) {
            int child = (k << 1) + 1; // assume left child is least
            Object c = queue[child];
            int right = child + 1;
            if (right < size &&
                ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
                c = queue[child = right];
            if (key.compareTo((E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        queue[k] = key;
    }

JDK,常見數據結構解讀