Java數(shù)據(jù)結(jié)構(gòu)中雙向鏈表的實(shí)現(xiàn)
引言
雙向鏈表(Double Linked List)是一種常見的數(shù)據(jù)結(jié)構(gòu),它允許在鏈表中的任意位置進(jìn)行高效的插入和刪除操作。與單向鏈表不同,雙向鏈表中的每個(gè)節(jié)點(diǎn)不僅包含指向下一個(gè)節(jié)點(diǎn)的指針,還包含指向前一個(gè)節(jié)點(diǎn)的指針。這種結(jié)構(gòu)使得雙向鏈表在某些操作上比單向鏈表更加靈活和高效。
雙向鏈表的結(jié)構(gòu)
在Java中,雙向鏈表可以通過一個(gè)內(nèi)部類Node
來表示鏈表中的每個(gè)節(jié)點(diǎn)。每個(gè)節(jié)點(diǎn)包含三個(gè)屬性:
prev
:指向前一個(gè)節(jié)點(diǎn)的指針。next
:指向下一個(gè)節(jié)點(diǎn)的指針。data
:節(jié)點(diǎn)存儲(chǔ)的數(shù)據(jù)。
static class Node { Node prev; // 指向前一個(gè)節(jié)點(diǎn) Node next; // 指向下一個(gè)節(jié)點(diǎn) int data; // 節(jié)點(diǎn)數(shù)據(jù) public Node(Node prev, Node next, int data) { this.prev = prev; this.next = next; this.data = data; } }
雙向鏈表的初始化
在雙向鏈表的初始化過程中,我們通常會(huì)創(chuàng)建兩個(gè)哨兵節(jié)點(diǎn)(head
和tail
),它們分別代表鏈表的頭和尾。這兩個(gè)節(jié)點(diǎn)不存儲(chǔ)實(shí)際數(shù)據(jù),僅用于簡(jiǎn)化鏈表的操作。
public DoubleLinkedList() { head = new Node(null, null, 0); tail = new Node(null, null, 0); head.next = tail; tail.prev = head; }
雙向鏈表的基本操作
1. 插入操作
雙向鏈表支持在鏈表的任意位置插入新節(jié)點(diǎn)。以下是幾個(gè)常見的插入操作:
在鏈表頭部插入節(jié)點(diǎn):
public void addfirst(int data) { add(0, data); }
在鏈表尾部插入節(jié)點(diǎn):
public void addlast(int data) { Node prev = tail.prev; Node newNode = new Node(prev, tail, data); prev.next = newNode; tail.prev = newNode; }
在指定位置插入節(jié)點(diǎn):
public void add(int index, int data) { Node prev = findNode(index - 1); Node next = prev.next; Node newNode = new Node(prev, next, data); prev.next = newNode; next.prev = newNode; if (prev == null) { throw illegalIndex(index); } }
2. 刪除操作
雙向鏈表同樣支持在鏈表的任意位置刪除節(jié)點(diǎn)。以下是幾個(gè)常見的刪除操作:
刪除鏈表頭部的節(jié)點(diǎn):
public void removefirst() { remove(0); }
刪除鏈表尾部的節(jié)點(diǎn):
public void removelast() { Node removeNode = tail.prev; Node prev = removeNode.prev; prev.next = tail; tail.prev = prev; }
刪除指定位置的節(jié)點(diǎn):
public void remove(int index) { Node prev = findNode(index - 1); Node removeNode = prev.next; Node next = removeNode.next; prev.next = next; next.prev = prev; if (prev == null || removeNode == tail) { throw illegalIndex(index); } }
3. 查找操作
雙向鏈表可以通過索引查找節(jié)點(diǎn):
public Node findNode(int index) { int i = -1; for (Node current = head; current != tail; current = current.next, i++) { if (i == index) { return current; } } return null; }
4. 遍歷操作
雙向鏈表可以通過遍歷操作輸出鏈表中的所有節(jié)點(diǎn)數(shù)據(jù):
public void traverse() { Node current = head.next; while (current != tail) { System.out.println(current.data); current = current.next; } }
5. 修改操作
根據(jù)索引修改節(jié)點(diǎn)的的值
public void set(int index, int data) { Node node = findNode(index); if (node == null || node == tail) { throw illegalIndex(index); } node.data = data; }
應(yīng)用場(chǎng)景
雙向鏈表在許多場(chǎng)景中都有廣泛的應(yīng)用,例如:
- LRU緩存:雙向鏈表可以用于實(shí)現(xiàn)LRU(Least Recently Used)緩存算法,通過鏈表的插入和刪除操作來維護(hù)緩存中的數(shù)據(jù)。
- 瀏覽器歷史記錄:瀏覽器的歷史記錄可以通過雙向鏈表來實(shí)現(xiàn),用戶可以向前或向后導(dǎo)航。
- 文本編輯器:在文本編輯器中,雙向鏈表可以用于實(shí)現(xiàn)光標(biāo)的移動(dòng)和文本的插入與刪除。
源碼
下面是上面提到的所有源碼
package school.doublelinkedlist; import java.util.Iterator; import java.util.NoSuchElementException; /** * 文件名: null.java * 作者: 20526 * 創(chuàng)建時(shí)間: 2024/9/9 17:28 * 描述:雙向鏈表 */ public class DoubleLinkedList implements Iterator<Integer> { private Node head;//頭哨兵節(jié)點(diǎn) private Node tail;//尾哨兵節(jié)點(diǎn) public DoubleLinkedList() { head = new Node(null, null, 0); tail = new Node(null, null, 0); head.next = tail; tail.prev = head; } @Override public boolean hasNext() { Node current = head.next; return current!= tail; } @Override public Integer next() { Node current = head.next; if (!hasNext()) { throw new NoSuchElementException(); } int data = current.data; current = current.next; return data; } static class Node { Node prev;//指向前一個(gè)節(jié)點(diǎn) Node next;//指向下一個(gè)節(jié)點(diǎn) int data;//節(jié)點(diǎn)數(shù)據(jù) public Node(Node prev, Node next, int data) { this.prev = prev; this.next = next; this.data = data; } } public Node findNode(int index) { int i =-1; for(Node current = head;current!=tail;current=current.next,i++){ if(i==index){ return current; } } return null; } public void traverse() { Node current = head.next; while (current != tail) { System.out.println(current.data); current = current.next; } } public void addfirst(int data) { add(0, data); } public void addlast(int data) { Node prev = tail.prev; Node newNode = new Node(prev, tail, data); prev.next = newNode; } public void add(int index, int data) { Node prev = findNode(index-1); Node next = prev.next; Node newNode = new Node(prev, next, data); prev.next = newNode; next.prev = newNode; if (prev == null){ throw illegalIndex(index); } } public void removefirst() { remove(0); } public void removelast() { Node removeNode = tail.prev; Node prev = removeNode.prev; prev.next = tail; tail.prev = prev; } public void remove(int index) { Node prev = findNode(index-1); Node removeNode = prev.next; Node next = removeNode.next; prev.next = next; next.prev = prev; if (prev == null){ throw illegalIndex(index); } if (removeNode == tail){ throw illegalIndex(index); } } public void set(int index, int data) { Node node = findNode(index); if (node == null || node == tail) { throw illegalIndex(index); } node.data = data; } private IllegalArgumentException illegalIndex(int index) { throw new IllegalArgumentException( String.format("Index: [%d]不合法%n", index)); } }
測(cè)試類
package school.doublelinkedlist; import org.junit.Test; public class DoubleLinkedListTest { @Test public void test() { DoubleLinkedList list = new DoubleLinkedList(); list.add(0,1); list.add(1,2); list.add(2,3); list.addlast(4); list.traverse(); } }
總結(jié)
雙向鏈表是一種靈活且高效的數(shù)據(jù)結(jié)構(gòu),它通過每個(gè)節(jié)點(diǎn)中的前后指針,使得在鏈表中的任意位置進(jìn)行插入和刪除操作變得簡(jiǎn)單。希望對(duì)你有所幫助。
到此這篇關(guān)于Java數(shù)據(jù)結(jié)構(gòu)中雙向鏈表的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java雙向鏈表內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java程序員的10道常見的XML面試問答題(XML術(shù)語詳解)
包括web開發(fā)人員的Java面試在內(nèi)的各種面試中,XML面試題在各種編程工作的面試中很常見。XML是一種成熟的技術(shù),經(jīng)常作為從一個(gè)平臺(tái)到其他平臺(tái)傳輸數(shù)據(jù)的標(biāo)準(zhǔn)2014-04-04SpringBoot連接MySql數(shù)據(jù)庫的原理及代碼示例
SpringBoot是一款流行的Java開發(fā)框架,它可以輕松地連接各種類型的數(shù)據(jù)庫,包括關(guān)系型數(shù)據(jù)庫和非關(guān)系型數(shù)據(jù)庫,本文將介紹SpringBoot是如何連接數(shù)據(jù)庫的,包括其原理和代碼示例,需要的朋友可以參考下2023-07-07Java實(shí)現(xiàn)簡(jiǎn)單推箱子游戲
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)推箱子游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06基于mybatis-plus-generator實(shí)現(xiàn)代碼自動(dòng)生成器
這篇文章專門為小白準(zhǔn)備了入門級(jí)mybatis-plus-generator代碼自動(dòng)生成器,可以提高開發(fā)效率。文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-05-05使用IDEA工具配置和運(yùn)行vue項(xiàng)目及遇到的坑
這篇文章主要介紹了使用IDEA工具配置和運(yùn)行vue項(xiàng)目及遇到的坑,需要的朋友可以參考下2018-09-09手把手教你使用Java實(shí)現(xiàn)在線生成pdf文檔
在實(shí)際的業(yè)務(wù)開發(fā)的時(shí)候,常常會(huì)需要把相關(guān)的數(shù)據(jù)信息,通過一些技術(shù)手段生成對(duì)應(yīng)的PDF文件,然后返回給用戶。本文將手把手教大家如何利用Java實(shí)現(xiàn)在線生成pdf文檔,需要的可以參考一下2022-03-03java UDP實(shí)現(xiàn)一個(gè)聊天工具的示例代碼
這篇文章主要介紹了java UDP實(shí)現(xiàn)一個(gè)聊天工具的示例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01