日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

链表数据结构图解 和 代码实现

發布時間:2024/4/18 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 链表数据结构图解 和 代码实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

項目中經常會用到LinkedList集合來存儲數據,打算寫一篇LinkedList的源碼解析,而LinkedList是基于鏈表結構存儲數據的,這篇博文將解析鏈表數據結構,包括單向鏈表和雙向鏈表;

1:單向鏈表:

單向鏈表的鏈表對象維護了一個 first 引用,該引用指向節點鏈表中的第一個節點對象,每個節點對象維護一個 next 引用,next引用指向下一個節點對象;(這里注意:是引用指向的是節點對象:節點對象包含存儲的數據和next引用)

以下是單向鏈表的圖解:

java代碼實現如下:

public class LinkedListDemo1 { //表示整個鏈表對象private Node first; //鏈表對象的第一個引用public LinkedListDemo1(){}public Node getFirst() {return first;}public void setFirst(Node first) {this.first = first;}class Node{ //節點對象Item item; //存儲的數據對象Node next; //下一個節點對象的引用public Item getItem() {return item;}public void setItem(Item item) {this.item = item;}public Node getNext() {return next;}public void setNext(Node next) {this.next = next;}} }

當需要在首位置插入元素時,圖解如下:first 引用指向需要插入到鏈表中的節點對象,新的節點對象的next引用指向原先的首節點對象;

java代碼實現如下:

//插入對象到鏈表首位置public void insertFirst(Item item){//創建鏈表對象LinkedListDemo1 list=new LinkedListDemo1();//原來的首個節點暫存在:用oldFirst引用指向Node oldFirst=first;//創建需要插入的節點對象Node newNode=new Node();newNode.item=item;//新節點對象的next引用指向原先的首節點對象newNode.next=oldFirst;}

 當然這里的插入沒有考慮首位置的節點對象為null的情況,插入到其他位置的節點實現原理和插入到首位置的基本差不多;

下面接收雙向鏈表的實現原理:

鏈表對象中維護一個first 引用和 last引用,分別指向鏈表中的首末節點對象;每個節點對象維護 存儲的數據對象引用,prev和next引用,用來指向前后節點對象;

雙向鏈表的圖解:

java代碼實現鏈表對象如下:

public class LinkedListDemo2 {private Node first;private Node last;public LinkedListDemo2(){}public Node getFirst() {return first;}public void setFirst(Node first) {this.first = first;}public Node getLast() {return last;}public void setLast(Node last) {this.last = last;}class Node{Item item;Node prev;Node next;public Item getItem() {return item;}public void setItem(Item item) {this.item = item;}public Node getPrev() {return prev;}public void setPrev(Node prev) {this.prev = prev;}public Node getNext() {return next;}public void setNext(Node next) {this.next = next;}} }

雙向鏈表插入元素到首位:

圖解:

java代碼實現:

public void insertFirst(Item item){//暫存原先首節點對象Node oldFirst=first;//創建新的節點對象Node newNode=new Node();newNode.item=item;newNode.next=first;//first引用指向新節點對象first=newNode;//原先的節點對象的prev引用指向新節點對象oldFirst.prev=newNode;}

到此,單向鏈表結構和雙向鏈表結構就解析完了,下面將解析 LinkedList 的源碼:

LinkedList是基于雙向鏈表數據結構來存儲數據的,以下是對LinkedList ?的 屬性,構造器 ,add(E e),remove(index),get(Index),set(inde,e)進行源碼分析:

屬性:

123456789101112131415transient?int?size =?0;????//記錄集合的大小????/**?????* Pointer to first node.?????* Invariant: (first == null && last == null) ||?????*??????????? (first.prev == null && first.item != null)?????*/????transient?Node<E> first;??//指向首節點對象????/**?????* Pointer to last node.?????* Invariant: (first == null && last == null) ||?????*??????????? (last.next == null && last.item != null)?????*/????transient?Node<E> last;????//指向末節點對象

2構造器:

1public?LinkedList() {???//構造空的LinkedList對象<br>}
123public?LinkedList(Collection<??extends?E> c) {???//構造對象,將集合元素添加到新集合中<br>?????? this();???????addAll(c);???}

3:方法:add(E e)

1234public?boolean?add(E e) {????????linkLast(e);????????return?true;????}

linkedLast(e) 源碼

1234567891011121314/**?????* Links e as last element.?????*/????void?linkLast(E e) {????????final?Node<E> l = last;??????//將原來的最末節點對象暫存 l 引用????????final?Node<E> newNode =?new?Node<>(l, e,?null);? /構建新的Node對象????????last = newNode;??????????????//將鏈表對象的last引用指向新增的節點元素????????if?(l ==?null)??????????????????????????first = newNode;?????????//如果不存在之前指向的節點,則first引用指向新創建的節點對象????????else????????????l.next = newNode;????????//存在前一個節點,之前最后節點對象的next指向新建的節點對象????????size++;??????????????????????//結合的長度加1????????modCount++;????}

Node對象的構造器如下:

1234567891011private?static?class?Node<E> {????????E item;????????Node<E> next;????????Node<E> prev;????????Node(Node<E> prev, E element, Node<E> next) {??//參數為 l:之前的最后一個節點, element:需要新增的元素, next null????????????this.item = element;???//要增加的元素????????????this.next = next;??????//新增節點的next指向為null????????????this.prev = prev;??????//新增節點的prev指向之前的節點????????}????}

remove方法:

1234public?E remove(int?index) {????//刪除指定索引的元素???????checkElementIndex(index);???//檢查是否索引越界???????return?unlink(node(index));????}
1node(index) 的源碼如下:
123456789101112131415Node<E> node(int?index) {????????// assert isElementIndex(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;????????}????}

這里有點繁瑣,舉個具體的實例說明:比如需要刪除index=5;的節點對象,假設結合的長度為20

則調用 node(5) 方法后返回的是什么呢?假設Node(0) 為起始位置  

此時:初始:x=Node(0),當i=0 ? x=Node(1) ? ?i=1 ? x=Node(2)…… 當i=5-1 ?x=Node(5) ? 此時就定位到了需要刪除的節點對象 即 Node(index)

接下來調用: ? unlink(node(index)) ?繼續以index=5為例

12345678910111213141516171819202122232425E unlink(Node<E> x) {????????// assert x != null;????????final?E element = x.item;?????//Node(5).data????????final?Node<E> next = x.next;??//next=Node(6)????????final?Node<E> prev = x.prev;??//prev=Node(4)????????if?(prev ==?null) {????????????first = next;????????}?else?{????????????prev.next = next;???????//Node(4).next=Node(6)????????????x.prev =?null;??????????//Node(5).prev=null????????}????????if?(next ==?null) {????????????last = prev;????????}?else?{????????????next.prev = prev;???????// Node(6).prev=Node(4)????????????x.next =?null;??????????//Node(5).next=null? 回收????????}????????x.item =?null;?????????????//Node(5)=null????????size--;????????modCount++;????????return?element;????}

這樣就完成了 ?Node(index-1).next=Node(index+1) ? Node(index+1).prev=Node(index-1) ? Node(index).data=null ?Node(index).prev=null ?Node(index).next=null ?完成了刪除動作 ?刪除相應的索引的節點

刪除第一個節點和刪除最后一個節點的原理類似;

Get(int index) 方法:

123public?E get(int?index) {????????checkElementIndex(index);???//檢查索引是否越界????????return?node(index).item;????//node(index) 在刪除的方法中分析過,返回索引為index的節點對象, 所以get方法 返回的是該索引節點的存儲數據對象
1}

set(index,e) 方法:

12345public?E set(int?index, E element) {????????checkElementIndex(index);????????Node<E> x = node(index);?????//調用node(index)放回Node(index)????????E oldVal = x.item;??????????????????x.item = element;????????????//將 Node(index)的引用指向新的對象
1return?oldVal; }

 到此LinkedList的源碼分析結束了:

mark:使用LinkedList 時,使用的是鏈表結構,當調用add()方法時,默認添加到最后一個,集合不需要擴充,減少內存消耗;

但是當LinkedList 進行指定索引的查詢,元素替換,刪除,需要對集合從first指向開始進行遍歷一遍才能進行,有相應的計算復雜度;使用時應當考慮到這一點 


總結

以上是生活随笔為你收集整理的链表数据结构图解 和 代码实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。