最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何實(shí)現(xiàn)Java中一個(gè)簡單的LinkedList

 更新時(shí)間:2017年02月16日 09:08:17   作者:byhieg  
LinkedList與ArrayList都是List接口的具體實(shí)現(xiàn)類。下面將介紹如何實(shí)現(xiàn)一個(gè)簡單的LinkedList,具有很好的參考價(jià)值,下面跟著小編一起來看下吧

LinkedList與ArrayList都是List接口的具體實(shí)現(xiàn)類。LinkedList與ArrayList在功能上也是大體一致,但是因?yàn)閮烧呔唧w的實(shí)現(xiàn)方式不一致,所以在進(jìn)行一些相同操作的時(shí)候,其效率也是有差別的。

對于抽象的數(shù)據(jù)結(jié)構(gòu)——線性表而言,線性表分為兩種,一種是順序存儲結(jié)構(gòu)的順序表,另一種是通過指針來描述其邏輯位置的鏈表。

針對于具體的Java實(shí)現(xiàn):

  1. 順序存儲的順序表是用數(shù)組來實(shí)現(xiàn)的,以數(shù)組為基礎(chǔ)進(jìn)行封裝各種操作而形成的List為ArrayList
  2. 鏈表是用指針來描述其邏輯位置,在Java中以雙向鏈表為基礎(chǔ)進(jìn)行封裝各種操作而形成的List為LinkedList

針對插入與刪除操作,ArrayList每插入一個(gè)元素,首先需要判斷數(shù)組的空間夠不夠,不夠要進(jìn)行擴(kuò)容,在有足夠的空間的基礎(chǔ)上,在指定的index位置上插入元素,但是該index及以后的元素都要后移。雖然刪除操作不需要判斷空間夠不夠,但同樣需要該index及以后的元素向前移動,這些移動的操作會增加時(shí)間的復(fù)雜度。但是對于LinkedList就不一樣,因?yàn)槭褂弥羔榿碇甘酒溥壿嫷奈恢?,所以插入與刪除的操作的時(shí)間復(fù)雜度都是 ** O(1) **

雖然對于ArrayList而言,插入與刪除的時(shí)間復(fù)雜度很高,但是對于查找指定位置的元素這種操作而言,就非常的快,因?yàn)榭梢酝ㄟ^數(shù)組直接得到該下標(biāo)對應(yīng)的元素。反而,LinkedList而言,無法直接返回指定位置的元素,需要一個(gè)個(gè)查詢,其時(shí)間的復(fù)雜度就是 ** O(n) **

如何實(shí)現(xiàn)Java的ArrayList經(jīng)典實(shí)體類一樣,實(shí)現(xiàn)的目的主要在于練手以及掌握官方實(shí)現(xiàn)的原理和一些技巧,因此很多需要與其他類配合的方法和功能,就先不在這里實(shí)現(xiàn)如iterator等

所以,實(shí)現(xiàn)的LinkedList的方法如下:

add方法

get方法

indexOf方法

remove方法

與實(shí)現(xiàn)ArrayList的名字一樣,為SimpleLinkedList。源碼地址,歡迎star,fork

構(gòu)建一個(gè)雙向鏈表

構(gòu)建的代碼如下:

 private static class Node<E>{
 E item;
 Node<E> next;
 Node<E> prev;
 public Node(E item, Node<E> next, Node<E> prev) {
 this.item = item;
 this.next = next;
 this.prev = prev;
 }
 } 

常規(guī)的雙向鏈表的構(gòu)建方法,一個(gè)數(shù)字域存放數(shù)組,一個(gè)前指針指向一個(gè)Node類型的元素,一個(gè)后指針指向一個(gè)Node類型的元素。

對于LinkedList的實(shí)現(xiàn)而言,還需要以下三個(gè)成員變量

 private int size;
 private Node<E> first;
 private Node<E> last;

Add方法

這里實(shí)現(xiàn)的add方法是簡單的add(E e)以及add(int index,E e)兩個(gè)方法,addAll()將其他集合轉(zhuǎn)換LinkedList的方法,暫時(shí)放到以后去實(shí)現(xiàn)。

add方法兩個(gè)重載方法,其分別對應(yīng)不同的添加方式。先說add(E e)方法的實(shí)現(xiàn)。

 public boolean add(E element) {
 addAtLast(element);
 return true;
 }

不指定位置添加元素,則默認(rèn)添加到了鏈表的最后。addAtLast的核心代碼如下:

 private void addAtLast(E element) {
 Node<E> l = last;
 Node<E> node = new Node<E>(element, null, l);
 last = node;
 if (l == null) {
 first = node;
 } else {
 l.next = node;
 }
 size++;
 }

首先找到最后一位的Node元素,然后根據(jù)element創(chuàng)建一個(gè)新的Node元素,其next指向?yàn)閚ull,prev指向?yàn)樽詈笠晃籒ode元素。在創(chuàng)建完Node元素之后,last就變成了先創(chuàng)建的Node元素,接下來只需要把新node元素加到鏈表中即可。即讓l對象(原最后一位,現(xiàn)倒數(shù)第二位元素的next指針,指向新node元素)。至此,新node元素的next指向null,prev指向倒數(shù)第二個(gè)元素,倒數(shù)第二個(gè)元素的next指向新node,就將node成功加入鏈表。

上述的操作也可以看出,其插入的操作非常省時(shí)間,比起ArrayList,擴(kuò)容,移動元素快很多。

add的第二個(gè)重載方法 add(int index ,E e),先看代碼實(shí)現(xiàn):

 public void add(int index, E element) {
 checkRangeForAdd(index);
 if (index == size) {
 addAtLast(element);
 } else {
 Node<E> l = node(index);
 addBeforeNode(element, l);
 }
 }

首先判斷要插入的index是否在范圍內(nèi),在的話,再執(zhí)行后續(xù)的add操作。如果要插入的index剛好是最后一位,則執(zhí)行上面講的addAtLast,如果不是,則得到index所對應(yīng)的Node元素,執(zhí)行addBeforeNode。

獲取index所對應(yīng)的Node元素,是node方法,代碼如下:

 private Node<E> node(int index) {
 if (index < (size << 1)) {
 Node<E> cursor = first;
 for (int i = 0; i < index; i++) {
 cursor = cursor.next;
 }
 return cursor;
 } else {
 Node<E> cursor = last;
 for (int i = size - 1; i > index; i--) {
 cursor = cursor.prev;
 }
 return cursor;
 }
 }

這里的查找采用二分查找,節(jié)省查找時(shí)間,而且也應(yīng)用到了雙向鏈表的特點(diǎn)。首先判斷index在前一半的范圍內(nèi),還是后一半的范圍內(nèi)。如果是前一半,則游標(biāo)Node初始為first,用游標(biāo)Node元素的next,不斷指向index所在的元素。如果是后一半,則游標(biāo)Node初始為last,用游標(biāo)Node元素的prev,不斷指向index所在的元素。

在指定元素的前面插入新節(jié)點(diǎn)的addBeforeNode的方法如下:

 private void addBeforeNode(E element, Node<E> specifiedNode) {
 Node<E> preNode = specifiedNode.prev;
 Node<E> newNode = new Node<>(element, specifiedNode, preNode);
 if (preNode == null) {
 first = newNode;
 } else {
 preNode.next = newNode;
 }
 specifiedNode.prev = newNode;
 size++;
 }

插入的方式很簡單,新節(jié)點(diǎn)的prev是原index元素的prev,新節(jié)點(diǎn)的next是原index元素。剩下的操作是把該node放到鏈表中,讓原index元素的prev的next為新節(jié)點(diǎn),但是要判斷preNode是不是空,是的話,表示newNode為第一個(gè)元素,就是first。

至此,一個(gè)add方法,就實(shí)現(xiàn)完了。

get方法

get方法在有了上述node方法之后,就非常的簡單。代碼如下:

 public E get(int index) {
 checkRange(index);
 return node(index).item;
 }

checkRange檢查index是否不在范圍內(nèi)。

 private void checkRange(int index) {
 if (index >= size || index < 0) {
 throw new IndexOutOfBoundsException("指定index超過界限");
 }
 }

indexOf方法

indexOf(Object o)用來得到指定元素的下標(biāo)。

 public int indexOf(Object element) {
 Node<E> cursor = first;
 int count = 0;
 while (cursor != null) {
 if (element != null) {
 if (element.equals(cursor.item)) {
  return count;
 }
 }else{
 if (cursor.item == null) {
  return count;
 }
 }
 count ++;
 cursor = cursor.next;
 }
 return -1;
 }

與ArrayList一樣,從第一位開始查找,首先先判斷element是不是null,分成兩種情況。

remove方法

remove方法與add方法一樣,同樣有兩個(gè)重載的方法,remove(Object o)與remove(int index)

先看簡單的remove(int index)方法,代碼如下:

 public E remove(int index) {
 checkRange(index);
 return deleteLink(index);
 }

deleteLink是將該index所對應(yīng)的節(jié)點(diǎn)的鏈接刪除的方法,其代碼如下:

 private E deleteLink(int index) {
 Node<E> l = node(index);
 E item = l.item;
 Node<E> prevNode = l.prev;
 Node<E> nextNode = l.next;
 if (prevNode == null) {
 first = nextNode;
 }else{
 prevNode.next = nextNode;
 l.next = null;
 }
 if (nextNode == null) {
 last = prevNode;
 }else{
 nextNode.prev = prevNode;
 l.prev = null;
 }
 size--;
 l.item = null;
 return item;
 }

首先獲得該index對應(yīng)的Node元素,得到該Node元素的前一個(gè)元素和后一個(gè)元素。接下來,只需要將前一個(gè)元素和后一個(gè)元素直接相連即可,其他只需要額外判斷前一個(gè)元素和后一個(gè)元素是否為null就行。在判斷前一個(gè)元素是否為null的時(shí)候,只需要操作前一個(gè)元素,在判斷后一個(gè)元素是否為null的時(shí)候,也只需要操作后一個(gè)元素。最后,將要刪除的元素各個(gè)引用至為null。

remove另一個(gè)重載方法remove(Object o),在實(shí)現(xiàn)了indexOf和deleteLink方法之后,就非常簡單。

 public boolean remove(Object o) {
 int index = indexOf(o);
 if (index < 0){
 return false;
 }
 deleteLink(index);
 return true;
 }

獲取該元素對應(yīng)對應(yīng)的下標(biāo),然后執(zhí)行deleteLink方法,完成remove操作。

總結(jié)

至此,一個(gè)功能簡單的LinkedList就實(shí)現(xiàn)完成了,全部的代碼可以看源碼地址

以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持腳本之家!

相關(guān)文章

  • SpringMVC 單文件上傳與多文件上傳實(shí)例

    SpringMVC 單文件上傳與多文件上傳實(shí)例

    這篇文章主要介紹了SpringMVC 單文件上傳與多文件上傳實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • InterlliJ IDEA2020新建java web項(xiàng)目找不到Static Web的解決

    InterlliJ IDEA2020新建java web項(xiàng)目找不到Static Web的解決

    這篇文章主要介紹了InterlliJ IDEA2020新建java web項(xiàng)目找不到Static Web的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • mybatis中關(guān)于mapper的使用以及注意事項(xiàng)

    mybatis中關(guān)于mapper的使用以及注意事項(xiàng)

    這篇文章主要介紹了mybatis中關(guān)于mapper的使用以及注意事項(xiàng),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Java SpringBoot攔截器詳解

    Java SpringBoot攔截器詳解

    這篇文章主要介紹了Java SpringBoot攔截器的使用方法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-10-10
  • 例題詳解Java?dfs與記憶化搜索和分治遞歸算法的使用

    例題詳解Java?dfs與記憶化搜索和分治遞歸算法的使用

    遞歸指函數(shù)調(diào)用自身。常用的遞歸算法有dfs(深度優(yōu)先搜索)、記憶化搜索和分治,接下來將用幾個(gè)算法題來帶你熟練掌握它
    2022-04-04
  • 一文讀懂JavaWeb前后端數(shù)據(jù)交互

    一文讀懂JavaWeb前后端數(shù)據(jù)交互

    本文主要介紹了一文讀懂JavaWeb前后端數(shù)據(jù)交互,包括HTTP請求與響應(yīng)、JSON數(shù)據(jù)格式以及常用的數(shù)據(jù)傳輸技術(shù),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • Spring?IOC容器的Bean管理基于注解屬性注入方式

    Spring?IOC容器的Bean管理基于注解屬性注入方式

    這篇文章主要為大家介紹了Spring?IOC容器的Bean管理基于注解屬性注入方式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • java阻塞隊(duì)列BlockingQueue詳細(xì)解讀

    java阻塞隊(duì)列BlockingQueue詳細(xì)解讀

    這篇文章主要介紹了java阻塞隊(duì)列BlockingQueue詳細(xì)解讀,在新增的Concurrent包中,BlockingQueue很好的解決了多線程中,如何高效安全“傳輸”數(shù)據(jù)的問題,通過這些高效并且線程安全的隊(duì)列類,為我們快速搭建高質(zhì)量的多線程程序帶來極大的便利,需要的朋友可以參考下
    2023-10-10
  • Java面試必備之ArrayList陷阱解析

    Java面試必備之ArrayList陷阱解析

    昨天小楓接到了一個(gè)公司的面試電話,其中一道面試題覺得有點(diǎn)意思,在這里和大家一起分享下。面試題是ArrayList如何刪除指定元素。乍聽很簡單的問題,但是如果沒有實(shí)際踩過坑很容易掉進(jìn)面試官的陷阱中,我們一起來分析下吧
    2022-02-02
  • java List去掉重復(fù)元素的幾種方式(小結(jié))

    java List去掉重復(fù)元素的幾種方式(小結(jié))

    這篇文章主要介紹了java List去掉重復(fù)元素的幾種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06

最新評論

镇雄县| 东源县| 土默特左旗| 汾阳市| 芒康县| 邮箱| 渭南市| 龙山县| 扎赉特旗| 房产| 高淳县| 合水县| 连江县| 新化县| 驻马店市| 盐亭县| 禹州市| 墨玉县| 崇礼县| 武乡县| 泾阳县| 元朗区| 仙游县| 固镇县| 中山市| 永嘉县| 印江| 连州市| 三门县| 汝州市| 安溪县| 安国市| 水富县| 潢川县| 高青县| 启东市| 即墨市| 阜宁县| 遵义市| 花莲县| 屯昌县|