溫故----ArrayList、LinkedList & HashMap之看菜吃飯校翔,量體裁衣

ArrayList

Java的ArrayList是一個動態(tài)擴(kuò)容的數(shù)組弟跑,開發(fā)中最常用的數(shù)據(jù)結(jié)構(gòu)之一;

特點

1.具有數(shù)組的快速隨機(jī)訪問能力防症,根據(jù)索引查找訪問元素只需O(1);
2.ArrayList中的操作不是線程安全的孟辑,多線程請考慮Vector或者CopyOnWriteArrayList.
3.關(guān)于ArrayList重點關(guān)注下新增元素引起的擴(kuò)容或者刪除哎甲、插入元素引發(fā)的數(shù)組元素移位邏輯:

   //先看下數(shù)組的末尾追加add函數(shù)如何處理擴(kuò)容:
    public boolean add(E e) {
       //新增元素首先需要計算當(dāng)前數(shù)組的容量是否夠再塞入一個元素(size為當(dāng)前數(shù)組實際元素個數(shù))
        ensureCapacityInternal(size + 1); 
        elementData[size++] = e;  //容量保證之后,直接末尾新增
        return true;
    }
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //這里的判斷體現(xiàn)了默認(rèn)構(gòu)造的數(shù)組初始容量為DEFAULT_CAPACITY=10  
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
       //數(shù)組沒有足夠的空間饲嗽,需要調(diào)用grow擴(kuò)容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    /**
     * 擴(kuò)容邏輯是每次增加原有容量的一半即到1.5*oldCapacity炭玫;
     * 1.5倍還是不夠則直接擴(kuò)容到申請的minCapacity大小,最后安全判斷容量是否超出上限
     */
    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);
    }
    //最終使用Arrays copyOf函數(shù)貌虾,創(chuàng)建新容量的數(shù)組并且將原有數(shù)組整個copy到新數(shù)組
    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;
    }


    //再看下數(shù)組指定位置插入:
    public void add(int index, E element) {
        rangeCheckForAdd(index);
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //前面容量保證邏輯跟上面一致
        //多一次copy為將index及其后的所有元素础嫡,整體后移到index+1,空出index這個位置給新增元素
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

   //刪除元素對象酝惧,會使用元素的equal方法進(jìn)行比較查找
   public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
ArrayList總結(jié):

ArrayList默認(rèn)構(gòu)造容量為10,可指定容量構(gòu)造或者通過集合構(gòu)造相應(yīng)容量的數(shù)組伯诬;
新增元素可能引起的擴(kuò)容邏輯:嘗試1.5倍擴(kuò)容晚唇,若是1.5倍依然夠則直接擴(kuò)容到新增元素所需的最小容量,擴(kuò)容引發(fā)創(chuàng)建新的容量大小數(shù)組并且將數(shù)組元素整體copy到新數(shù)組的開銷盗似。
刪除或者指定位置新增:引發(fā)額外的數(shù)組元素整體copy移位開銷哩陕。
刪除元素對象使用equal方法進(jìn)行比較.

LinkedList

LinkedList也是非常常用的數(shù)據(jù)結(jié)構(gòu),在java的實現(xiàn)是一個雙向的鏈表:

LinkedList結(jié)構(gòu)圖

1.雙向鏈表赫舒,快速增刪悍及,查詢&隨機(jī)訪問效率低
2.線程不安全
3.遍歷操作,推薦使用foreach & 迭代器Iterator遍歷接癌,get(int index)效率低

    //從節(jié)點的結(jié)構(gòu)看出來包含next心赶、prev兩個分別指向前一節(jié)點和后一節(jié)點的引用可以看出LinkedList是一個雙向鏈表的實現(xiàn).
    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

    //持有了鏈表的頭結(jié)點、尾結(jié)點方便快速訪問操作鏈表的頭缺猛、尾
    transient Node<E> first;
    transient Node<E> last;

    linkList.addFirst(e);
    linkList.addLast(e);
    linkList.removeFirst();
    linkList.removeLast();
    linkList.getLast();
    linkList.getFirst();
    public void push(E e) {
        addFirst(e);
    }
    public E pop() {
        return removeFirst();
    }
    //看下指定位置插入node的實現(xiàn):
    public void add(int index, E element) {
        checkPositionIndex(index);
        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }
    //這個node(index)函數(shù)返回index處的node節(jié)點
    Node<E> node(int index) {
        //如果index<0.5*size從頭結(jié)點往后查找,否則從尾結(jié)點往前查找
        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

為何通過get(index)效率低缨叫?

  //對于數(shù)組使用這種for + i的遍歷非常常見而且也沒啥毛病,數(shù)組隨機(jī)索引訪問O(1)
  for(int i=0; i<length; i++) {  
    arrayList[i];
  }

    //若是用于LinkedList荔燎,看看linkedList的get(i)實現(xiàn)就會發(fā)現(xiàn)每次都需要從頭指針或尾指針開始往計算索引值耻姥,list越長效率越低
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }
    Node<E> node(int index) {
        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

foreach在編譯的時候編譯器會自動將對for這個關(guān)鍵字的使用轉(zhuǎn)化為對目標(biāo)的迭代器的使用
三種遍歷方式效率分析:https://www.cnblogs.com/gsm340/p/9243916.html

LinkedList總結(jié):

LinkedList就是一個線程不安全的雙向鏈表,并且記錄了鏈表的頭和尾有咨,提供了大量的頭和尾的操作方法琐簇。在首位節(jié)點插入、刪除時間復(fù)雜度O(1)座享,指定位置插入或者訪問查找指定元素都需要O(n)

HashMap

算了---> HashMap新起一篇文章來寫吧

溫故----HashMap原理補(bǔ)坑

參考內(nèi)容

CSDN - 淺談ArrayList動態(tài)擴(kuò)容
Java LinkedList的實現(xiàn)原理圖文詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末婉商,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子征讲,更是在濱河造成了極大的恐慌据某,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诗箍,死亡現(xiàn)場離奇詭異癣籽,居然都是意外死亡挽唉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進(jìn)店門筷狼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓶籽,“玉大人,你說我怎么就攤上這事埂材∷芩常” “怎么了?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵俏险,是天一觀的道長严拒。 經(jīng)常有香客問我,道長竖独,這世上最難降的妖魔是什么裤唠? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮莹痢,結(jié)果婚禮上种蘸,老公的妹妹穿的比我還像新娘。我一直安慰自己竞膳,他們只是感情好航瞭,可當(dāng)我...
    茶點故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坦辟,像睡著了一般刊侯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上长窄,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天滔吠,我揣著相機(jī)與錄音,去河邊找鬼挠日。 笑死疮绷,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嚣潜。 我是一名探鬼主播冬骚,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼懂算!你這毒婦竟也來了只冻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤计技,失蹤者是張志新(化名)和其女友劉穎喜德,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體垮媒,經(jīng)...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡舍悯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年航棱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片萌衬。...
    茶點故事閱讀 38,747評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡饮醇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出秕豫,到底是詐尸還是另有隱情朴艰,我是刑警寧澤,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布混移,位于F島的核電站祠墅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏歌径。R本人自食惡果不足惜饵隙,卻給世界環(huán)境...
    茶點故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沮脖。 院中可真熱鬧,春花似錦芯急、人聲如沸勺届。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽免姿。三九已至,卻和暖如春榕酒,著一層夾襖步出監(jiān)牢的瞬間胚膊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工想鹰, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留紊婉,地道東北人。 一個月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓辑舷,卻偏偏與公主長得像喻犁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子何缓,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,658評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 原文地址 Java集合 Java集合框架:是一種工具類肢础,就像是一個容器可以存儲任意數(shù)量的具有共同屬性的對象。 Ja...
    gyl_coder閱讀 978評論 0 8
  • ? 在編寫java程序中碌廓,我們最常用的除了八種基本數(shù)據(jù)類型传轰,String對象外還有一個集合類,在我們的的程序中到處...
    Java幫幫閱讀 1,410評論 0 6
  • ArrayList 詳解 底層是數(shù)組谷婆,查詢快增刪慢慨蛙,線程不安全辽聊,效率高。初始化長度10 說一下ArrayList底...
    奇點一氪閱讀 397評論 0 0
  • Java SE 基礎(chǔ): 封裝股淡、繼承身隐、多態(tài) 封裝: 概念:就是把對象的屬性和操作(或服務(wù))結(jié)合為一個獨立的整體,并盡...
    Jayden_Cao閱讀 2,103評論 0 8
  • - 這應(yīng)該就是傳說中的nice body 就算穿牛仔褲也遮不住小姐姐的性感 還有這眼睛,是自帶了美顏功能吧 - 二...
    旺咔閱讀 391評論 0 0