面經手冊 · 第8篇《LinkedList插入速度比ArrayList快?你確定嗎?》

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作者:小傅哥"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"博客:"},{"type":"link","attrs":{"href":"https://bugstack.cn","title":""},"content":[{"type":"text","text":"https://bugstack.cn"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"沉澱、分享、成長,讓自己和他人都能有所收穫!😄"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"一、前言"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"你以爲考你個數據結構是要造火箭?"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"🚕汽車75馬力就夠奔跑了,那你怎麼還想要2.0渦輪+9AT呢?大橋兩邊的護欄你每次走的時候都會去摸嗎?那怎麼沒有護欄的大橋你不敢上呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"很多時候,你額外的能力纔是自身價值的體現,不要以爲你的能力就只是做個業務開發每天CRUD,並不是產品讓你寫CRUD,而是因爲你的能力只能產品功能設計成CRUD。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"就像數據結構、算法邏輯、源碼技能,它都是可以爲你的業務開發賦能的,也是寫出更好、更易擴展程序的根基,所以學好這份知識非常有必要。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"*本文涉及了較多的代碼和實踐驗證圖稿,歡迎關注公衆號:"},{"type":"codeinline","content":[{"type":"text","text":"bugstack蟲洞棧"}]},{"type":"text","text":",回覆下載得到一個鏈接打開後,找到ID:19🤫獲取!*"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"二、面試題"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"謝飛機"}]},{"type":"text","text":",ArrayList資料看了吧?嗯,那行問問你哈🦀"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"**"},{"type":"codeinline","content":[{"type":"text","text":"問"}]},{"type":"text","text":"**:ArrayList和LinkedList,都用在什麼場景呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"**"},{"type":"codeinline","content":[{"type":"text","text":"答"}]},{"type":"text","text":"**:啊,這我知道了。ArrayList是基於數組實現、LinkedList是基於雙向鏈表實現,所以基於數據結構的不同,遍歷和查找多的情況下用ArrayList、插入和刪除頻繁的情況下用LinkedList。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"**"},{"type":"codeinline","content":[{"type":"text","text":"問"}]},{"type":"text","text":"**:嗯,那LinkedList的插入效率一定比ArrayList好嗎?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"**"},{"type":"codeinline","content":[{"type":"text","text":"答"}]},{"type":"text","text":"**:對,好!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"送你個飛機✈,回去等消息吧!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其實,飛機回答的也不是不對,只是不全面。出門後不甘心買瓶"},{"type":"codeinline","content":[{"type":"text","text":"肥宅水"}]},{"type":"text","text":"又回來,跟面試官聊了2個點,要到了兩張圖,如下;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a0/a0859bf032ce61303febdaa319ed3787.png","alt":"小傅哥 bugstack.cn & ArrayList頭插、尾插、中間","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ab/abaf829ec3c081bff9dde3d415e71b3c.png","alt":"小傅哥 bugstack.cn & LinkedList頭插、尾插、中間","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如圖,分別是;"},{"type":"codeinline","content":[{"type":"text","text":"10萬"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"100萬"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"1000萬"}]},{"type":"text","text":",數據在兩種集合下不同位置的插入效果,"},{"type":"text","marks":[{"type":"strong"}],"text":"所以:"},{"type":"text","text":",不能說LinkedList插入就快,ArrayList插入就慢,還需要看具體的操作情況。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來我們帶着數據結構和源碼,具體分析下。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"三、數據結構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Linked + List = 鏈表 + 列表 = LinkedList = 鏈表列表"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/af/af95f005c785ae68062f55ab22cf67c4.png","alt":"小傅哥 bugstack.cn & LinkedList數據結構","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"LinkedList,是基於鏈表實現,由雙向鏈條next、prev,把數據節點穿插起來。所以,在插入數據時,是不需要像我們上一章節介紹的ArrayList那樣,擴容數組。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但,又不能說所有的插入都是高效,比如中間區域插入,他還需要遍歷元素找到插入位置。具體的細節,我們在下文的源碼分析中進行講解,也幫"},{"type":"codeinline","content":[{"type":"text","text":"謝飛機"}]},{"type":"text","text":"掃除疑惑。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"四、源碼分析"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1. 初始化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"與ArrayList不同,LinkedList初始化不需要創建數組,因爲它是一個鏈表結構。而且也沒有傳給構造函數初始化多少個空間的入參,例如這樣是不可以的,如下;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/01/01cb71720ba60176d0be178a4fdb671a.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"但是"},{"type":"text","text":",構造函數一樣提供了和ArrayList一些相同的方式,來初始化入參,如下這四種方式;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Test\npublic void test_init() {\n // 初始化方式;普通方式\n LinkedList list01 = new LinkedList();\n list01.add(\"a\");\n list01.add(\"b\");\n list01.add(\"c\");\n System.out.println(list01);\n \n // 初始化方式;Arrays.asList\n LinkedList list02 = new LinkedList(Arrays.asList(\"a\", \"b\", \"c\"));\n System.out.println(list02);\n \n // 初始化方式;內部類\n LinkedList list03 = new LinkedList()\\\\{\n {add(\"a\");add(\"b\");add(\"c\");}\n \\\\};\n System.out.println(list03);\n \n // 初始化方式;Collections.nCopies\n LinkedList list04 = new LinkedList(Collections.nCopies(10, 0));\n System.out.println(list04);\n}\n\n// 測試結果\n\n[a, b, c]\n[a, b, c]\n[a, b, c]\n[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n\nProcess finished with exit code 0"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這些方式都可以初始化操作,按需選擇即可。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2. 插入"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"LinkedList的插入方法比較多,List中接口中默認提供的是add,也可以指定位置插入。但在LinkedList中還提供了頭插"},{"type":"codeinline","content":[{"type":"text","text":"addFirst"}]},{"type":"text","text":"和尾插"},{"type":"codeinline","content":[{"type":"text","text":"addLast"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關於插入這部分就會講到爲什麼;有的時候LinkedList插入更耗時、有的時候ArrayList插入更好。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"2.1 頭插"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先來看一張數據結構對比圖,回顧下ArrayList的插入也和LinkedList插入做下對比,如下;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/1a/1a6dc852f5dd31014ca4ecdb7ee3a03a.png","alt":"小傅哥 bugstack.cn & 插入對比","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"看上圖我們可以分析出幾點;"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"ArrayList 頭插時,需要把數組元素通過"},{"type":"codeinline","content":[{"type":"text","text":"Arrays.copyOf"}]},{"type":"text","text":"的方式把數組元素移位,如果容量不足還需要擴容。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"LinkedList 頭插時,則不需要考慮擴容以及移位問題,直接把元素定位到首位,接點鏈條鏈接上即可。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"2.1.1 源碼"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏我們再對照下"},{"type":"codeinline","content":[{"type":"text","text":"LinkedList"}]},{"type":"text","text":"頭插的源碼,如下;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private void linkFirst(E e) {\n final Node f = first;\n final Node newNode = new Node<>(null, e, f);\n first = newNode;\n if (f == null)\n last = newNode;\n else\n f.prev = newNode;\n size++;\n modCount++;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"first,首節點會一直被記錄,這樣就非常方便頭插。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"插入時候會創建新的節點元素,"},{"type":"codeinline","content":[{"type":"text","text":"new Node<>(null, e, f)"}]},{"type":"text","text":",緊接着把新的頭元素賦值給first。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"之後判斷f節點是否存在,不存在則把頭插節點作爲最後一個節點、存在則用f節點的上一個鏈條prev鏈接。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後記錄size大小、和元素數量modCount。"},{"type":"text","marks":[{"type":"italic"}],"text":"modCount用在遍歷時做校驗,modCount != expectedModCount"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"2.1.2 驗證"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"ArrayList、LinkeList,頭插源碼驗證"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Test\npublic void test_ArrayList_addFirst() {\n ArrayList list = new ArrayList();\n long startTime = System.currentTimeMillis();\n for (int i = 0; i < 10000000; i++) {\n list.add(0, i);\n }\n System.out.println(\"耗時:\" + (System.currentTimeMillis() - startTime));\n}\n\n@Test\npublic void test_LinkedList_addFirst() {\n LinkedList list = new LinkedList();\n long startTime = System.currentTimeMillis();\n for (int i = 0; i < 10000000; i++) {\n list.addFirst(i);\n }\n System.out.println(\"耗時:\" + (System.currentTimeMillis() - startTime));\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"比對結果:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/45/45619ec5a8f16282796b560aa2191acf.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏我們分別驗證,10萬、100萬、1000萬的數據量,在頭插時的一個耗時情況。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如我們數據結構對比圖中一樣,ArrayList需要做大量的位移和複製操作,而LinkedList的優勢就體現出來了,耗時只是實例化一個對象。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"2.2 尾插"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先來看一張數據結構對比圖,回顧下ArrayList的插入也和LinkedList插入做下對比,如下;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b7/b73e94871d1a781813ab9d30632a35b0.png","alt":"小傅哥 bugstack.cn & 插入對比","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"看上圖我們可以分析出幾點;"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"ArrayList 尾插時,是不需要數據位移的,比較耗時的是數據的擴容時,需要拷貝遷移。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"LinkedList 尾插時,與頭插相比耗時點會在對象的實例化上。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"2.2.1 源碼"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏我們再對照下"},{"type":"codeinline","content":[{"type":"text","text":"LinkedList"}]},{"type":"text","text":"尾插的源碼,如下;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"void linkLast(E e) {\n final Node l = last;\n final Node newNode = new Node<>(l, e, null);\n last = newNode;\n if (l == null)\n first = newNode;\n else\n l.next = newNode;\n size++;\n modCount++;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"與頭插代碼相比幾乎沒有什麼區別,只是first換成last"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"耗時點只是在創建節點上,"},{"type":"codeinline","content":[{"type":"text","text":"Node"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"2.2.2 驗證"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"ArrayList、LinkeList,尾插源碼驗證"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Test\npublic void test_ArrayList_addLast() {\n ArrayList list = new ArrayList();\n long startTime = System.currentTimeMillis();\n for (int i = 0; i < 10000000; i++) {\n list.add(i);\n }\n System.out.println(\"耗時:\" + (System.currentTimeMillis() - startTime));\n}\n\n@Test\npublic void test_LinkedList_addLast() {\n LinkedList list = new LinkedList();\n long startTime = System.currentTimeMillis();\n for (int i = 0; i < 1000000; i++) {\n list.addLast(i);\n }\n System.out.println(\"耗時:\" + (System.currentTimeMillis() - startTime));\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"比對結果:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/07/077b09fed550d5d1ee9883351e7f06a2.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏我們分別驗證,10萬、100萬、1000萬的數據量,在尾插時的一個耗時情況。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如我們數據結構對比圖中一樣,ArrayList 不需要做位移拷貝也就不那麼耗時了,而LinkedList則需要創建大量的對象。"},{"type":"text","marks":[{"type":"italic"}],"text":"所以這裏ArrayList尾插的效果更好一些。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"2.3 中間插"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先來看一張數據結構對比圖,回顧下ArrayList的插入也和LinkedList插入做下對比,如下;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/79/79a25987fc75ddc43aad611e066650e7.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"看上圖我們可以分析出幾點;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"ArrayList 中間插入,首先我們知道他的定位時間複雜度是O(1),比較耗時的點在於數據遷移和容量不足的時候擴容。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"LinkedList 中間插入,鏈表的數據實際插入時候並不會怎麼耗時,但是它定位的元素的時間複雜度是O(n),所以這部分以及元素的實例化比較耗時。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"2.3.1 源碼"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏看下LinkedList指定位置插入的源碼;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"使用add(位置、元素)方法插入:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public void add(int index, E element) {\n checkPositionIndex(index);\n if (index == size)\n linkLast(element);\n else\n linkBefore(element, node(index));\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"位置定位node(index):"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"Node node(int index) {\n // assert isElementIndex(index);\n if (index < (size >> 1)) {\n Node x = first;\n for (int i = 0; i < index; i++)\n x = x.next;\n return x;\n } else {\n Node x = last;\n for (int i = size - 1; i > index; i--)\n x = x.prev;\n return x;\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"size >> 1"}]},{"type":"text","text":",這部分的代碼判斷元素位置在左半區間,還是右半區間,在進行循環查找。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"執行插入:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"void linkBefore(E e, Node succ) {\n // assert succ != null;\n final Node pred = succ.prev;\n final Node newNode = new Node<>(pred, e, succ);\n succ.prev = newNode;\n if (pred == null)\n first = newNode;\n else\n pred.next = newNode;\n size++;\n modCount++;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"找到指定位置插入的過程就比較簡單了,與頭插、尾插,相差不大。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"整個過程可以看到,插入中比較耗時的點會在遍歷尋找插入位置上。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"2.3.2 驗證"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"ArrayList、LinkeList,中間插入源碼驗證"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Test\npublic void test_ArrayList_addCenter() {\n ArrayList list = new ArrayList();\n long startTime = System.currentTimeMillis();\n for (int i = 0; i < 10000000; i++) {\n list.add(list.size() >> 1, i);\n }\n System.out.println(\"耗時:\" + (System.currentTimeMillis() - startTime));\n}\n\n@Test\npublic void test_LinkedList_addCenter() {\n LinkedList list = new LinkedList();\n long startTime = System.currentTimeMillis();\n for (int i = 0; i < 1000000; i++) {\n list.add(list.size() >> 1, i);\n }\n System.out.println(\"耗時:\" + (System.currentTimeMillis() - startTime));\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"比對結果:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ff/ff7c74924eb6b3c97e9f8a328f8029db.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏我們分別驗證,10萬、100萬、1000萬的數據量,在中間插時的一個耗時情況。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到Linkedlist在中間插入時,遍歷尋找位置還是非常耗時了。所以不同的情況下,需要選擇不同的List集合做業務。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3. 刪除"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"講了這麼多插入的操作後,刪除的知識點就很好理解了。與ArrayList不同,刪除不需要拷貝元素,LinkedList是找到元素位置,把元素前後鏈連接上。基本如下圖;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/91/91702b06e1c6e5e4874819b5d313b962.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"確定出要刪除的元素x,把前後的鏈接進行替換。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果是刪除首尾元素,操作起來會更加容易,這也就是爲什麼說插入和刪除快。但中間位置刪除,需要遍歷找到對應位置。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"3.1 刪除操作方法"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ff/ff6dfc78120564bc512e2f6f936527af.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"源碼:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Test\npublic void test_remove() {\n LinkedList list = new LinkedList();\n list.add(\"a\");\n list.add(\"b\");\n list.add(\"c\");\n \n list.remove();\n list.remove(1);\n list.remove(\"a\");\n list.removeFirst();\n list.removeLast();\n list.removeAll(Arrays.asList(\"a\", \"b\"));\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"3.2 源碼"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"刪除操作的源碼都差不多,分爲刪除首尾節點與其他節點時候,對節點的解鏈操作。這裏我們舉例一個刪除其他位置的源碼進行學習,如下;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"list.remove(\"a\");"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public boolean remove(Object o) {\n if (o == null) {\n for (Node x = first; x != null; x = x.next) {\n if (x.item == null) {\n unlink(x);\n return true;\n }\n }\n } else {\n for (Node x = first; x != null; x = x.next) {\n if (o.equals(x.item)) {\n unlink(x);\n return true;\n }\n }\n }\n return false;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這一部分是元素定位,和"},{"type":"codeinline","content":[{"type":"text","text":" unlink(x)"}]},{"type":"text","text":"解鏈。循環查找對應的元素,這部分沒有什麼難點。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"unlink(x)解鏈"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"E unlink(Node x) {\n // assert x != null;\n final E element = x.item;\n final Node next = x.next;\n final Node prev = x.prev;\n \n if (prev == null) {\n first = next;\n } else {\n prev.next = next;\n x.prev = null;\n }\n \n if (next == null) {\n last = prev;\n } else {\n next.prev = prev;\n x.next = null;\n }\n \n x.item = null;\n size--;\n modCount++;\n return element;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這部分源碼主要有以下幾個知識點;"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"獲取待刪除節點的信息;元素item、元素下一個節點next、元素上一個節點prev。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"如果上個節點爲空則把待刪除元素的下一個節點賦值給首節點,否則把待刪除節點的下一個節點,賦值給待刪除節點的上一個節點的子節點。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"同樣待刪除節點的下一個節點next,也執行2步驟同樣操作。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"最後是把刪除節點設置爲null,並扣減size和modeCount數量。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"4. 遍歷"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來說下遍歷,ArrayList與LinkedList的遍歷都是通用的,基本包括5種方式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏我們先初始化出待遍歷的集合1千萬數據;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"int xx = 0;\n@Before\npublic void init() {\n for (int i = 0; i < 10000000; i++) {\n list.add(i);\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"4.1 普通for循環"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Test\npublic void test_LinkedList_for0() {\n long startTime = System.currentTimeMillis();\n for (int i = 0; i < list.size(); i++) {\n xx += list.get(i);\n }\n System.out.println(\"耗時:\" + (System.currentTimeMillis() - startTime));\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"4.2 增強for循環"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Test\npublic void test_LinkedList_for1() {\n long startTime = System.currentTimeMillis();\n for (Integer itr : list) {\n xx += itr;\n }\n System.out.println(\"耗時:\" + (System.currentTimeMillis() - startTime));\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"4.3 Iterator遍歷"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Test\npublic void test_LinkedList_Iterator() {\n long startTime = System.currentTimeMillis();\n Iterator iterator = list.iterator();\n while (iterator.hasNext()) {\n Integer next = iterator.next();\n xx += next;\n }\n System.out.println(\"耗時:\" + (System.currentTimeMillis() - startTime))\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"4.4 forEach循環"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Test\npublic void test_LinkedList_forEach() {\n long startTime = System.currentTimeMillis();\n list.forEach(integer -> {\n xx += integer;\n });\n System.out.println(\"耗時:\" + (System.currentTimeMillis() - startTime));\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"4.5 stream(流)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Test\npublic void test_LinkedList_stream() {\n long startTime = System.currentTimeMillis();\n list.stream().forEach(integer -> {\n xx += integer;\n });\n System.out.println(\"耗時:\" + (System.currentTimeMillis() - startTime));\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"那麼"},{"type":"text","text":",以上這5種遍歷方式誰最慢呢?按照我們的源碼學習分析下吧,歡迎留下你的答案在評論區!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"五、總結"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ArrayList與LinkedList都有自己的使用場景,如果你不能很好的確定,那麼就使用ArrayList。但如果你能確定你會在集合的首位有大量的插入、刪除以及獲取操作,那麼可以使用LinkedList,因爲它都有相應的方法;"},{"type":"codeinline","content":[{"type":"text","text":"addFirst"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"addLast"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"removeFirst"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"removeLast"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"getFirst"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"getLast"}]},{"type":"text","text":",這些操作的時間複雜度都是O(1),非常高效。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"LinkedList的鏈表結構不一定會比ArrayList節省空間,首先它所佔用的內存不是連續的,其次他還需要大量的實例化對象創造節點。雖然不一定節省空間,但鏈表結構也是非常優秀的數據結構,它能在你的程序設計中起着非常優秀的作用,例如可視化的鏈路追蹤圖,就是需要鏈表結構,並需要每個節點自旋一次,用於串聯業務。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"程序的精髓往往就是數據結構的設計,這能爲你的程序開發提供出非常高的效率改變。可能目前你還不能用到,但萬一有一天你需要去造🚀火箭了呢?"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"六、系列文章"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://bugstack.cn/interview/2020/08/27/%E9%9D%A2%E7%BB%8F%E6%89%8B%E5%86%8C-%E7%AC%AC7%E7%AF%87-ArrayList%E4%B9%9F%E8%BF%99%E4%B9%88%E5%A4%9A%E7%9F%A5%E8%AF%86-%E4%B8%80%E4%B8%AA%E6%8C%87%E5%AE%9A%E4%BD%8D%E7%BD%AE%E6%8F%92%E5%85%A5%E5%B0%B1%E6%8A%8A%E8%B0%A2%E9%A3%9E%E6%9C%BA%E9%9D%A2%E6%99%95%E4","title":""},"content":[{"type":"text","text":"ArrayList也這麼多知識?一個指定位置插入就把謝飛機面暈了!"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://bugstack.cn/interview/2020/08/07/%E9%9D%A2%E7%BB%8F%E6%89%8B%E5%86%8C-%E7%AC%AC3%E7%AF%87-HashMap%E6%A0%B8%E5%BF%83%E7%9F%A5%E8%AF%86-%E6%89%B0%E5%8A%A8%E5%87%BD%E6%95%B0-%E8%B4%9F%E8%BD%BD%E5%9B%A0%E5%AD%90-%E6%89%A9%E5%AE%B9%E9%93%BE%E8%A1%A8%E6%8B%86%E5%88%86-%E6%B7%B1%E5%BA%A6%E5%AD%A6%E","title":""},"content":[{"type":"text","text":"HashMap核心知識,擾動函數、負載因子、擴容鏈表拆分,深度學習"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://bugstack.cn/itstack-code-life/2020/04/11/%E5%B7%A5%E4%BD%9C%E4%B8%A4%E5%B9%B4%E7%AE%80%E5%8E%86%E5%86%99%E6%88%90%E8%BF%99%E6%A0%B7-%E8%B0%81%E8%A6%81%E4%BD%A0%E5%91%80.html","title":""},"content":[{"type":"text","text":"簡歷寫成這樣,誰要你呀!"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://bugstack.cn/itstack-code-life/2020/03/31/%E5%A4%A7%E5%AD%A6%E5%9B%9B%E5%B9%B4%E5%88%B0%E6%AF%95%E4%B8%9A%E5%B7%A5%E4%BD%9C5%E5%B9%B4%E7%9A%84%E5%AD%A6%E4%B9%A0%E8%B7%AF%E7%BA%BF%E8%B5%84%E6%BA%90%E6%B1%87%E6%80%BB.html","title":""},"content":[{"type":"text","text":"工作5年的學習路線資源彙總"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://bugstack.cn/itstack-code-life/2020/07/25/12%E5%A4%A9-%E8%BF%99%E6%9C%AC-%E9%87%8D%E5%AD%A6Java%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-PDF%E4%B9%A6%E7%B1%8D%E4%B8%8B%E8%BD%BD%E9%87%8F9k-%E6%96%B0%E5%A2%9E%E7%B2%89%E4%B8%9D1400%E4%BA%BA-Github%E4%B8%8A%E5%85%A8%E7%90%83%E6%8E%A8%E8%8D%90%E6%A6%9C","title":""},"content":[{"type":"text","text":"懂設計模式才能面試到20k以上"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章