Java數(shù)據(jù)結(jié)構(gòu)之雙向鏈表的實現(xiàn)
1 雙向鏈表
1.1 雙向鏈表介紹
相較單鏈表,雙向鏈表除了data與next域,還多了一個pre域用于表示每個節(jié)點的前一個元素。這樣做給雙向鏈表帶來了很多優(yōu)勢:
單向鏈表查找的方向只能是一個方向,而雙向鏈表可以向前或者向后查找;
單鏈表如果想要實現(xiàn)刪除操作,需要找到待刪除節(jié)點的前一個節(jié)點。而雙向鏈表可以實現(xiàn)自我刪除。
雙向鏈表結(jié)構(gòu)示意圖如下:

1.2 雙向鏈表實現(xiàn)思路
與單鏈表實現(xiàn)類似,交集部分不再贅述,詳情可參考文章:Java數(shù)據(jù)結(jié)構(gòu):單鏈表的實現(xiàn)與面試題匯總
遍歷:
與單鏈表遍歷方式一樣,同時,雙向鏈表可以支持向前和向后兩種查找方式
添加:
添加到末尾
- 先找到雙向鏈表最后一個節(jié)點
- cur.next = newNode;
- newNode.pre = cur;
按照no順序添加
- 先判斷該鏈表是否為空,如果為空則直接添加
- 如果不為空則繼續(xù)處理
- 根據(jù)no遍歷鏈表,找到合適的位置
- newNode.next = cur.next;
- cur.next = newNode;
- newNode.pre = cur;
修改操作與單鏈表實現(xiàn)步驟一致
刪除操作:
- 雙向鏈表可以實現(xiàn)自我刪除
- 直接找到待刪除的節(jié)點
- cur.pre.next = cur.next;
- cur.next.pre = cur.pre;
- 需要特別注意是否為最后一個元素,如果為最后一個元素,cur.next為null,此時使用cur.next.pre會出現(xiàn)空指針異常,所以,如果為最后一個元素,則該步驟可以省略,cur.next為null即可。
以刪除紅色的2號節(jié)點為例:

2 雙向鏈表實現(xiàn)完整代碼
2.1 節(jié)點類 Student.java
/**
* @author 興趣使然黃小黃
* @version 1.0
* 學(xué)生類節(jié)點
*/
public class StudentNode {
public String no; //學(xué)號
public String name; //姓名
public int age; //年齡
public StudentNode pre; //指向前一個節(jié)點
public StudentNode next; //指向下一個節(jié)點
//構(gòu)造器
public StudentNode(String no, String name, int age ){
this.no = no;
this.name = name;
this.age = age;
}
//為了顯示方便
@Override
public String toString() {
return "StudentNode{" +
"no='" + no + '\'' +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
2.2 雙向鏈表實現(xiàn)類 StudentDoubleLinkedList.java
/**
* @author 興趣使然黃小黃
* @version 1.0
* 學(xué)生雙向鏈表的具體實現(xiàn)
*/
public class StudentDoubleLinkedList {
//定義頭節(jié)點
private StudentNode head = new StudentNode("", "", 0);
//獲取頭節(jié)點
public StudentNode getHead(){
return head;
}
//遍歷雙向鏈表的方法
public void showList(){
//判斷鏈表是否為空
if (head.next == null){
System.out.println("當(dāng)前鏈表為空");
return;
}
//遍歷 使用輔助指針
StudentNode temp = head;
while (temp != null){
//更新指針
temp = temp.next;
if (temp.next == null){
System.out.print(temp);
break;
}
System.out.print(temp + "--->");
}
}
//添加節(jié)點的方法
//添加到尾部
public void add(StudentNode newNode){
//先找到最后一個節(jié)點
StudentNode cur = head;
while (true){
//到達(dá)最后退出循環(huán)
if (cur.next == null){
break;
}
//更新指針
cur = cur.next;
}
//添加操作
newNode.next = cur.next; //也可以省略,因為恒為null
cur.next = newNode;
newNode.pre = cur;
}
//添加節(jié)點的方法
//根據(jù)學(xué)號順序添加
public void addByOrder(StudentNode newNode){
//如果當(dāng)前鏈表為空,則直接添加
if (head.next == null){
head.next = newNode;
newNode.pre = head;
return;
}
//按照學(xué)號找到對應(yīng)位置
StudentNode cur = head;
boolean flag = false; //標(biāo)識待添加的no是否存在
while (true){
if (cur.next == null){
//已經(jīng)到達(dá)鏈表的尾部
break;
} else if (Integer.parseInt(cur.next.no) == Integer.parseInt(newNode.no)){
//已經(jīng)存在
flag = true;
break;
}else if (Integer.parseInt(cur.next.no) > Integer.parseInt(newNode.no)){
//位置找到
break;
}
cur = cur.next;
}
if (flag){
System.out.println("當(dāng)前no已經(jīng)存在,無法添加!");
}else {
//添加操作
newNode.next = cur.next;
cur.next = newNode;
newNode.pre = cur;
}
}
//根據(jù)no學(xué)號修改學(xué)生信息
public void update(StudentNode studentNode){
if (head.next == null){
System.out.println("當(dāng)前鏈表為空, 無法修改");
return;
}
StudentNode temp = head.next;
boolean flag = false; //表示是否找到節(jié)點
while (true){
if (temp == null){
break;
}
if (temp.no == studentNode.no){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
temp.name = studentNode.name;
temp.age = studentNode.age;
System.out.println("更新成功!");
}else {
System.out.println("沒有找到");
}
}
//從雙向鏈表中刪除節(jié)點
public void delete(String no){
//直接找到對應(yīng)no的節(jié)點直接刪除
StudentNode cur = head.next;
boolean flag = false; //標(biāo)記是否找到
while (true){
if (cur == null){
break;
}
if (cur.no.equals(no)){
flag = true; //找到了
break;
}
cur = cur.next;
}
if (flag){
//刪除操作
//注意考慮最后一個節(jié)點后一個為空的情況
if (cur.next != null) {
cur.next.pre = cur.pre;
}
cur.pre.next = cur.next;
System.out.println("刪除成功!");
}else {
System.out.println( no + "節(jié)點不存在,無法刪除!");
}
}
}
2.3 測試類 StudentDoubleLinkedListDemo.java
/**
* @author 興趣使然黃小黃
* @version 1.0
* 雙向鏈表測試類
*/
public class DoubleLinkedListDemo {
public static void main(String[] args) {
StudentDoubleLinkedList doubleLinkedList = new StudentDoubleLinkedList();
doubleLinkedList.addByOrder(new StudentNode("1", "黃小黃", 20));
doubleLinkedList.addByOrder(new StudentNode("3", "懶羊羊", 20));
doubleLinkedList.addByOrder(new StudentNode("2", "沸羊羊", 25));
doubleLinkedList.addByOrder(new StudentNode("4", "美羊羊", 15));
System.out.println("遍歷:");
doubleLinkedList.showList();
//測試更新方法
System.out.println("\n更新編號為4的信息后:");
doubleLinkedList.update(new StudentNode("4", "禰豆子", 14));
doubleLinkedList.showList();
//測試刪除方法
System.out.println("\n刪除第一個和最后一個:");
doubleLinkedList.delete("1");
doubleLinkedList.delete("4");
doubleLinkedList.showList();
}
}
2.4 結(jié)果
遍歷:
StudentNode{no='1', name='黃小黃', age=20}--->StudentNode{no='2', name='沸羊羊', age=25}--->StudentNode{no='3', name='懶羊羊', age=20}--->StudentNode{no='4', name='美羊羊', age=15}
更新編號為4的信息后:
更新成功!
StudentNode{no='1', name='黃小黃', age=20}--->StudentNode{no='2', name='沸羊羊', age=25}--->StudentNode{no='3', name='懶羊羊', age=20}--->StudentNode{no='4', name='禰豆子', age=14}
刪除第一個和最后一個:
刪除成功!
刪除成功!
StudentNode{no='2', name='沸羊羊', age=25}--->StudentNode{no='3', name='懶羊羊', age=20}
Process finished with exit code 0
3 雙向鏈表小結(jié)
單向鏈表查找的方向只能為一個方向,雙向鏈表解決了這個缺點,可以實現(xiàn)雙向查找;
單鏈表進(jìn)行刪除操作必須找到待刪除元素的前一個元素,才能完成刪除操作。而雙向鏈表就簡單多了,只需要找到待刪除的節(jié)點,進(jìn)行自我刪除;
本節(jié)介紹了雙向鏈表的遍歷、添加、按順序添加、更新、刪除方法的實現(xiàn),可以嘗試像單鏈表篇一樣,嘗試求有效節(jié)點數(shù)量,以及如何逆序輸出雙向鏈表加強(qiáng)練習(xí)!
以上就是Java數(shù)據(jù)結(jié)構(gòu)之雙向鏈表的實現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Java數(shù)據(jù)結(jié)構(gòu)雙向鏈表的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
讓Java后臺MySQL數(shù)據(jù)庫能夠支持emoji表情的方法
最近開發(fā)的iOS項目因為需要用戶文本的存儲,自然就遇到了emoji等表情符號如何被mysql DB支持的問題。下面這篇文章主要介紹了關(guān)于讓Java后臺MySQL數(shù)據(jù)庫能夠支持emoji表情的方法,需要的朋友可以參考下。2017-03-03
Java Date與String的相互轉(zhuǎn)換詳解
這篇文章主要介紹了Java Date與String的相互轉(zhuǎn)換詳解的相關(guān)資料,需要的朋友可以參考下2017-02-02
Java JSON轉(zhuǎn)成List結(jié)構(gòu)數(shù)據(jù)
這篇文章主要介紹了Java JSON轉(zhuǎn)成List結(jié)構(gòu)數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
Java8函數(shù)式接口Predicate用法示例詳解
這篇文章主要為大家介紹了Java8函數(shù)式接口Predicate用法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
Java中spring boot 字符串判斷是否為空方法小結(jié)
這篇文章主要介紹了Java中spring boot字符串判斷是否為空,通過安裝依賴,結(jié)合實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-11-11

