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

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Algorithms_基础数据结构(03)_线性表之链表_双向链表

發(fā)布時(shí)間:2025/3/21 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Algorithms_基础数据结构(03)_线性表之链表_双向链表 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 大綱圖
  • 雙向鏈表
  • 雙向鏈表的基本結(jié)構(gòu)
  • 雙向鏈表的基本操作
    • 頭插
    • 尾插
    • 中間部位插入
    • 刪除頭部
    • 刪除尾部
    • 刪除中間位置的數(shù)據(jù)
    • 查找
    • 更新
    • Code
  • 總結(jié)


大綱圖


雙向鏈表

Algorithms_基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)(02)_鏈表&鏈表的應(yīng)用案例之單向鏈表中梳理了 單向鏈表的基本操作,接下來(lái)我們繼續(xù)來(lái)看下雙向鏈表吧。


雙向鏈表的基本結(jié)構(gòu)

單向鏈表只有一個(gè)方向,結(jié)點(diǎn)只有一個(gè)后繼指針next指向后面的結(jié)點(diǎn)。

雙向鏈表,顧名思義,它支持兩個(gè)方向,每個(gè)結(jié)點(diǎn)不止有一個(gè)后繼指針next指向后面的結(jié)點(diǎn),還有一個(gè)前驅(qū)指針prev指向前面的結(jié)點(diǎn)。

雙向鏈表需要額外的兩個(gè)空間來(lái)存儲(chǔ)后繼結(jié)點(diǎn)前驅(qū)結(jié)點(diǎn)的地址。所以,如果存儲(chǔ)同樣多的數(shù)據(jù),雙向鏈表要比單鏈表占用更多的內(nèi)存空間。

雖然兩個(gè)指針比較浪費(fèi)存儲(chǔ)空間,但可以支持雙向遍歷,這樣也帶來(lái)了雙向鏈表操作的靈活性。那相比單鏈表,雙向鏈表適合解決哪種問(wèn)題呢?

-----> B+Tree:Mysql索引 葉子節(jié)點(diǎn) 雙向鏈表


雙向鏈表的基本操作

頭插


尾插


中間部位插入


刪除頭部


刪除尾部


刪除中間位置的數(shù)據(jù)


查找

通常,雙向鏈表同單鏈表一樣,都僅有一個(gè)頭指針。所以雙鏈表查找指定元素的實(shí)現(xiàn)同單鏈表類(lèi)似,都是從表頭依次遍歷表中元素,直到找到對(duì)應(yīng)的元素為止。


更新

更改雙鏈表中指定結(jié)點(diǎn)數(shù)據(jù)域的操作那必須要先查找到該節(jié)點(diǎn),因此是在查詢(xún)的基礎(chǔ)上完成的。------>即:通過(guò)遍歷找到存儲(chǔ)有該數(shù)據(jù)元素的結(jié)點(diǎn),直接更改其數(shù)據(jù)域即可。


Code

/*** @author 小工匠* @version v1.0* @create 2020-01-03 06:08* @motto show me the code ,change the word* @blog https://artisan.blog.csdn.net/* @description**/public class ArtisanDoubleLinkedList {private ArtisanNode head; // head節(jié)點(diǎn)private ArtisanNode tail; // tail節(jié)點(diǎn) 為了方便直接獲取tail節(jié)點(diǎn),省去每一次都要遍歷的操作private int size; // 鏈表元素?cái)?shù)量/*** 雙向鏈表初始化*/public ArtisanDoubleLinkedList() {this.head = null;this.tail = null;}/*** 頭插* @param data*/public void add2Head(Object data) {ArtisanNode node = new ArtisanNode(data); // 新的Nodeif (this.head == null) { // 如果head節(jié)點(diǎn)為null, head和tail節(jié)點(diǎn)均為這個(gè)新的node節(jié)點(diǎn)this.tail = node;} else {// 將原來(lái)的頭節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)指向node, 將新節(jié)點(diǎn)的后驅(qū)節(jié)點(diǎn)指向headthis.head.pre = node;node.next = head;}this.head = node; // 將新的節(jié)點(diǎn)置為head節(jié)點(diǎn)size++;}/*** 尾插 (低效)** @param data*/public void add2Tail(Object data) {// 從頭部遍歷,找到最后的節(jié)點(diǎn),然后加到尾部ArtisanNode node = new ArtisanNode(data); // 要加入的節(jié)點(diǎn)ArtisanNode currentNode = head;if (currentNode == null){add2Head(data);}while(currentNode !=null){if (currentNode.next == null){ // 說(shuō)明找到了當(dāng)前的tail節(jié)點(diǎn)currentNode.next = node ;// 將當(dāng)前tail節(jié)點(diǎn)的next指針指向新的tail節(jié)點(diǎn)node.pre = currentNode; //新的tail節(jié)點(diǎn)的pre指向當(dāng)前tail節(jié)點(diǎn)節(jié)點(diǎn)this.tail = node;break;}else{currentNode = currentNode.next;}}size++;}/*** 尾插 (利用tail 無(wú)需遍歷 效率更高)** @param data*/public void add2Tail2(Object data) {// 已經(jīng)設(shè)置tail了,直接用即可,效率更高ArtisanNode node = new ArtisanNode(data); // 要加入的節(jié)點(diǎn)if (this.head == null){add2Head(data);}else {tail.next = node;node.pre = tail;tail = node;}}/**** @param postition* @param data*/public void add2Nth(int postition ,Object data) {ArtisanNode newNode = new ArtisanNode(data); // 新的NodeArtisanNode currentNode = head;if (postition == 0 ){ // 如果是0 ,添加到頭節(jié)點(diǎn)add2Head(data);}else {for (int i = 1; i < postition; i++) { // 找到要插入的位置的前面的節(jié)點(diǎn)currentNode = currentNode.next;}// 與后繼節(jié)點(diǎn)建立雙層邏輯關(guān)系newNode.next = currentNode.next;currentNode.next.pre = newNode;// 與前置節(jié)點(diǎn)建立雙層邏輯關(guān)系currentNode.next = newNode;newNode.pre = currentNode;}size++;}/*** 根據(jù)value 查找元素* @param data* @return*/public ArtisanNode find(Object data){ // 從頭遍歷ArtisanNode currentNode = head;while(currentNode != null){if (data.equals(currentNode.data)){printPreAndNextInfo(currentNode);break;}else{currentNode = currentNode.next;}}return currentNode;}/*** 刪除頭部節(jié)點(diǎn)*/public void deleteHead(){this.head = this.head.next; // 將當(dāng)前頭節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)置為頭節(jié)點(diǎn)this.head.pre = null; // 將前置節(jié)點(diǎn)置為nullsize--;}/*** 刪除尾部節(jié)點(diǎn)*/public void deleteTail(){ArtisanNode currentNode = this.head;ArtisanNode previousNode = null;while (currentNode != null){if (currentNode.next == null){currentNode.pre = null;// 最后一個(gè)節(jié)點(diǎn)的pre置為置為nullpreviousNode.next = null;// 前置節(jié)點(diǎn)的next指針置為nullthis.tail = previousNode; // 將當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)置為tail節(jié)點(diǎn)}else { // 如果當(dāng)前節(jié)點(diǎn)的next指針指向不為空,則把下個(gè)節(jié)點(diǎn)置為當(dāng)前節(jié)點(diǎn),繼續(xù)遍歷previousNode = currentNode;// 保存上一個(gè)節(jié)點(diǎn)的信息currentNode = currentNode.next;}}}/*** 刪除指定位置的節(jié)點(diǎn)* @param position*/public ArtisanNode deleteNth(int position){ArtisanNode currentNode = this.head;if (position == 0 ){deleteHead();}else {for (int i = 1 ; i < position ; i++){// 找到要?jiǎng)h除節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)currentNode = currentNode.next;}currentNode.next.next.pre = currentNode; // 將 要?jiǎng)h除節(jié)點(diǎn)的后一個(gè)節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn) 指向 當(dāng)前節(jié)點(diǎn)(要?jiǎng)h除的節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn))currentNode.next = currentNode.next.next; // 將 要?jiǎng)h除節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)的next指針指向 要?jiǎng)h除節(jié)點(diǎn)的后一個(gè)節(jié)點(diǎn)}size--;return currentNode.next ; // 返回刪除的節(jié)點(diǎn)}/*** 獲取tail節(jié)點(diǎn)* @return tail節(jié)點(diǎn)*/public ArtisanNode getTail(){System.out.println("tail節(jié)點(diǎn)的值為:" + this.tail.data );return this.tail;}/*** 獲取head節(jié)點(diǎn)* @return head節(jié)點(diǎn)*/public ArtisanNode getHead(){System.out.println("head節(jié)點(diǎn)的值為:" + this.head.data );return this.head;}/*** 打印鏈表中的數(shù)據(jù)*/public void print() {ArtisanNode currentNode = this.head;// 從head節(jié)點(diǎn)開(kāi)始遍歷while (currentNode != null) { // 循環(huán),節(jié)點(diǎn)不為空 輸出當(dāng)前節(jié)點(diǎn)的數(shù)據(jù)System.out.print(currentNode.data + " -> ");currentNode = currentNode.next; // 將當(dāng)前節(jié)點(diǎn)移動(dòng)到下一個(gè)節(jié)點(diǎn),循環(huán)直到為null}System.out.print("null");System.out.println();}/*** 打印前后節(jié)點(diǎn)信息* @param currentNode*/private void printPreAndNextInfo(ArtisanNode currentNode) {System.out.println("當(dāng)前節(jié)點(diǎn):" + currentNode.data);if (currentNode.pre != null){System.out.println("當(dāng)前節(jié)點(diǎn)【" + currentNode.data + "】的前驅(qū)節(jié)點(diǎn):" + currentNode.pre.data);}else{System.out.println("當(dāng)前節(jié)點(diǎn)【"+ currentNode.data + "】為head節(jié)點(diǎn)");}if (currentNode.next != null){System.out.println("當(dāng)前節(jié)點(diǎn)【"+ currentNode.data + "】的后繼節(jié)點(diǎn):" + currentNode.next.data);}else{System.out.println("當(dāng)前節(jié)點(diǎn)【"+ currentNode.data + "】為tail節(jié)點(diǎn)");}}public static void main(String[] args) {ArtisanDoubleLinkedList doubleLinkedList = new ArtisanDoubleLinkedList();doubleLinkedList.add2Head("artisanData96");doubleLinkedList.add2Head("artisanData97");doubleLinkedList.add2Head("artisanData99");doubleLinkedList.add2Head("artisanData98");doubleLinkedList.getTail();doubleLinkedList.add2Tail("artisanData100");doubleLinkedList.getTail();doubleLinkedList.print();doubleLinkedList.getHead();// doubleLinkedList.add2Nth(2,"addedDataByPos");// doubleLinkedList.add2Tail2(1); // doubleLinkedList.add2Tail2(2); // doubleLinkedList.add2Tail2(3); // doubleLinkedList.add2Tail2(4);// doubleLinkedList.print(); // // System.out.println("tail:" + doubleLinkedList.tail.data); // // doubleLinkedList.find("artisanData98"); // doubleLinkedList.deleteHead(); // doubleLinkedList.print(); // doubleLinkedList.find("artisanData99");// System.out.println("被刪除節(jié)點(diǎn):" + doubleLinkedList.deleteNth(1).data); // doubleLinkedList.print(); // doubleLinkedList.find("artisanData96");}/*** 雙向鏈表中的節(jié)點(diǎn)*/class ArtisanNode {ArtisanNode pre; // 前驅(qū)結(jié)點(diǎn)Object data; // 數(shù)據(jù)ArtisanNode next;// 后繼節(jié)點(diǎn)public ArtisanNode(Object data) {this.data = data;}} }

總結(jié)

重要區(qū)別:

  • 1.數(shù)組簡(jiǎn)單易用,在實(shí)現(xiàn)上使用的是連續(xù)的內(nèi)存空間,可以借助CPU的緩存機(jī)制,預(yù)讀數(shù)組中的數(shù)據(jù),所以訪(fǎng)問(wèn)效率更高。

  • 2.鏈表在內(nèi)存中并不是連續(xù)存儲(chǔ),所以對(duì)CPU緩存不友好,沒(méi)辦法有效預(yù)讀。

  • 3.數(shù)組的缺點(diǎn)是大小固定,一經(jīng)聲明就要占用整塊連續(xù)內(nèi)存空間。如果聲明的數(shù)組過(guò)大,系統(tǒng)可能沒(méi)有足夠的連續(xù)內(nèi)存空間分配給它, 導(dǎo)致“內(nèi)存不足(out ofmemory)”。如果聲明的數(shù)組過(guò)小,則可能出現(xiàn)不夠用的情況。注意下標(biāo)越界的問(wèn)題。

  • 4.動(dòng)態(tài)擴(kuò)容:數(shù)組需再申請(qǐng)一個(gè)更大的內(nèi)存空間,把原數(shù)組拷貝進(jìn)去,非常費(fèi)時(shí)。鏈表本身沒(méi)有大小的限制,天然地支持動(dòng)態(tài)擴(kuò)容,使用的時(shí)候也需要考慮占用內(nèi)存的問(wèn)題。

總結(jié)

以上是生活随笔為你收集整理的Algorithms_基础数据结构(03)_线性表之链表_双向链表的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。