什么是LinkedList?什么时候使用它呢?Java LinkedList结构、用法及源码解析
生活随笔
收集整理的這篇文章主要介紹了
什么是LinkedList?什么时候使用它呢?Java LinkedList结构、用法及源码解析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前言:我們學習java時都知道ArrayList實現List接口,LinkedList也實現List接口,但我們平時用的時候LinkedList卻很少被用到。那么,LinkedList什么時候該用到呢?內部又是如何實現的呢?本文對此進行詳細說明,希望能夠助君更上一層樓。
我們在使用ArrayList(動態數組)時有個明顯的缺點,就是當容量接近滿值的時候,會進行擴容,JDK默認擴容為1.5倍,那么,當數據量極大時,就會造成內存空間的大量浪費!
能否用到多少就申請多少內存?
沒錯LinkedList(鏈表)可以辦到這一點。
相信計算機專業的同學一定在數據結構課上學到過鏈表這種數據結構,鏈表是一種鏈式存儲的線性表,所有元素的內存地址不一定是連續的,內存結構如下:
上圖可以看出,我們的LinkedList每一個節點都有一個地址空間,用來存儲我們下一個節點的地址,雖然地址并不連續,但數據的存儲并不會受到任何影響。
在真正的設計中,為了查詢、添加、刪除的方便,我們的鏈表還需要有頭尾指針以及前驅指針
那么,讓我們歸結一下,鏈表首先需要一個頭指針,指向頭結點。一個尾節點,存儲尾節點。然后每個節點都需要一個存儲它的內部元素的屬性,一個指針指向他的前驅,一個節點指向他的后繼。
接著,我們先寫一下節點的類 👇
private static class Node<E> {E element;Node<E> prev;Node<E> next;public Node(Node<E> prev, E element, Node<E> next) {this.prev = prev;this.element = element;this.next = next;}
我們的節點是LinkedList的屬性,所以將節點放入我們的LinkedList中,如下👇
public class LinkedList<E> extends AbstractList<E> {private Node<E> first;private Node<E> last;private static class Node<E> {E element;Node<E> prev;Node<E> next;public Node(Node<E> prev, E element, Node<E> next) {this.prev = prev;this.element = element;this.next = next;}@Overridepublic String toString() {StringBuilder sb = new StringBuilder();if (prev != null) {sb.append(prev.element);} else {sb.append("null");}sb.append("_").append(element).append("_");if (next != null) {sb.append(next.element);} else {sb.append("null");}return sb.toString();}}@Overridepublic void clear() {size = 0;first = null;last = null;}@Overridepublic E get(int index) {return node(index).element;}@Overridepublic E set(int index, E element) {Node<E> node = node(index);E old = node.element;node.element = element;return old;}@Overridepublic void add(int index, E element) {rangeCheckForAdd(index);// size == 0// index == 0if (index == size) { // 往最后面添加元素Node<E> oldLast = last;last = new Node<>(oldLast, element, null);if (oldLast == null) { // 這是鏈表添加的第一個元素first = last;} else {oldLast.next = last;}} else {Node<E> next = node(index); Node<E> prev = next.prev; Node<E> node = new Node<>(prev, element, next);next.prev = node;if (prev == null) { // index == 0first = node;} else {prev.next = node;}}size++;}@Overridepublic E remove(int index) {rangeCheck(index);Node<E> node = node(index);Node<E> prev = node.prev;Node<E> next = node.next;if (prev == null) { // index == 0first = next;} else {prev.next = next;}if (next == null) { // index == size - 1last = prev;} else {next.prev = prev;}size--;return node.element;}@Overridepublic int indexOf(E element) {if (element == null) {Node<E> node = first;for (int i = 0; i < size; i++) {if (node.element == null) return i;node = node.next;}} else {Node<E> node = first;for (int i = 0; i < size; i++) {if (element.equals(node.element)) return i;node = node.next;}}return ELEMENT_NOT_FOUND;}/*** 獲取index位置對應的節點對象* @param index* @return*/private Node<E> node(int index) {rangeCheck(index);if (index < (size >> 1)) {Node<E> node = first;for (int i = 0; i < index; i++) {node = node.next;}return node;} else {Node<E> node = last;for (int i = size - 1; i > index; i--) {node = node.prev;}return node;}}@Overridepublic String toString() {StringBuilder string = new StringBuilder();string.append("size=").append(size).append(", [");Node<E> node = first;for (int i = 0; i < size; i++) {if (i != 0) {string.append(", ");}string.append(node);node = node.next;}string.append("]");return string.toString();}
相比較我們的ArrayList,LinkedList是否有什么特別的優點嗎?
我們的每種數據結構設計出來都有其特別的使用之處。總結一下:
-
數組(ArrayList)的隨機訪問速度非常快,但是指定位置添加、刪除操作時需要將后續元素全部順移。
-
LinkedList則恰恰相反,我們在使用鏈表做指定位置的添加刪除操作時,所需的操作非常少,但隨機訪問速度卻非常慢。
基于這些屬性,我們在使用中該如何選擇呢?
-
如果頻繁在尾部進行添加、刪除操作,動態數組、雙向鏈表均可選擇
-
如果頻繁在頭部進行添加、刪除操作,建議選擇使用雙向鏈表
-
如果有頻繁的(在任意位置)添加、刪除操作,建議選擇使用雙向鏈表
-
如果有頻繁的查詢操作(隨機訪問操作),建議選擇使用動態數組
所以,我們在應聘崗位的時候,會有一則能夠在不同情境使用不同的數據結構
選擇最合適的數據結構進行使用是非常重要的!
以上!!
總結
以上是生活随笔為你收集整理的什么是LinkedList?什么时候使用它呢?Java LinkedList结构、用法及源码解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一分钟带你了解什么是“复杂度” 算法
- 下一篇: Myeclipse中修改项目默认编码还是