使用 Java 的 DSA - 双向链表
双向链表基础知识
双向链表是链表的一种变体,与单链表相比,双向链表可以轻松地向前和向后导航。以下是理解双向链表概念的重要术语
链接 − 链表的每个链接都可以存储称为元素的数据。
下一个 − 链表的每个链接都包含一个指向下一个链接的链接,称为下一个。
上一个 − 链表的每个链接都包含一个指向上一个链接的链接,称为上一个。
链接列表 − LinkedList 包含指向第一个 Link(称为 First)和最后一个 Link(称为 Last)的连接链接。
双向链接列表表示

如上图所示,以下是需要考虑的重要点。
双向链接列表包含一个称为 first 和 last 的链接元素。
每个 Link 都带有一个数据字段和一个称为 next 的链接字段。
每个 Link 都使用其下一个链接与其下一个链接链接。
每个 Link 都使用其上一个链接与其上一个链接链接。
最后一个 Link 带有一个为 null 的 Link 来标记结束列表。
基本操作
以下是列表支持的基本操作。
插入 − 在列表开头添加一个元素。
删除 − 删除列表开头的一个元素。
插入最后一个 − 在列表末尾添加一个元素。
删除最后一个 − 从列表末尾删除一个元素。
在后面插入 − 在列表的某项后面添加一个元素。
删除 −使用键从列表中删除一个元素。
向前显示 − 以向前方式显示完整列表。
向后显示 − 以向后方式显示完整列表。
插入操作
以下代码演示了在双向链表开头的插入操作。
//在第一个位置插入链接 public void insertFirst(int key, int data){ //创建链接 Link link = new Link(key,data); if(isEmpty()){ //使其成为最后一个链接 last = link; }else { //更新第一个上一个链接 first.prev = link; } //将其指向旧的第一个链接 link.next = first; //将 first 指向新的第一个链接 first = link; }
删除操作
以下代码演示了双向链表开头的删除操作。
//删除第一个位置的链接 public Link deleteFirst(){ //保存对第一个链接的引用 Link tempLink = first; //如果只有一个链接 if(first.next == null){ last = null; }else { first.next.prev = null; } first = first.next; //返回删除的链接 return tempLink; }
在末尾插入操作
以下代码演示了在双向链表的最后一个位置插入操作。
//在最后一个位置插入链接 public void insertLast(int key, int data){ //创建链接 Link link = new Link(key,data); if(isEmpty()){ //使其成为最后一个链接 last = link; }else { //使链接成为新的最后一个链接 last.next = link; //将旧的最后一个节点标记为新链接的前一个 link.prev = last; } //将最后一个指向新的最后一个节点 last = link; }
演示
Link.java
package com.tutorialspoint.list; public class Link { public int key; public int data; public Link next; public Link prev; public Link(int key, int data){ this.key = key; this.data = data; } public void display(){ System.out.print("{"+key+","+data+"}"); } }
DoublyLinkedList.java
package com.tutorialspoint.list; public class DoublyLinkedList { //此链接始终指向第一个链接 private Link first; //此链接始终指向最后一个链接 private Link last; // 创建一个空的链接列表 public DoublyLinkedList(){ first = null; last = null; } //列表是否为空 public boolean isEmpty(){ return first == null; } //在第一个位置插入链接 public void insertFirst(int key, int data){ //创建链接 Link link = new Link(key,data); if(isEmpty()){ //使其成为最后一个链接 last = link; }else { //更新第一个上一个链接 first.prev = link; } //将其指向旧的第一个链接 link.next = first; //将 first 指向新的第一个链接 first = link; } //在最后位置插入链接 public void insertLast(int key, int data){ //创建链接 Link link = new Link(key,data); if(isEmpty()){ //使其成为最后一个链接 last = link; }else { //使链接成为新的最后一个链接 last.next = link; //将旧的最后一个节点标记为新链接的前一个 link.prev = last; } //将最后一个指向新的最后一个节点 last = link; } //删除第一个位置的链接 public Link deleteFirst(){ //保存对第一个链接的引用 Link tempLink = first; //如果只有一个链接 if(first.next == null){ last = null; }else { first.next.prev = null; } first = first.next; //返回删除的链接 return tempLink; } //删除最后一个位置的链接 public Link deleteLast(){ //保存对最后一个链接的引用 Link tempLink = last; //如果只有一个链接 if(first.next == null){ first = null; }else { last.prev.next = null; } last = last.prev; //返回删除的链接 return tempLink; } //从第一个到最后一个显示列表 public void displayForward(){ //从头开始 Link current = first; //导航到列表末尾 System.out.print("[ "); while(current != null){ //打印数据 current.display(); //移动到下一个项目 current = current.next; System.out.print(" "); } System.out.print(" ]"); } //从最后一个到第一个显示列表 public void displayBackward(){ //从最后一个开始 Link current = last; //导航到列表开头 System.out.print("[ "); while(current != null){ //打印数据 current.display(); //移动到下一个项目 current = current.prev; System.out.print(" "); } System.out.print(" ]"); } //删除指定键的链接 public Link delete(int key){ //从第一个链接开始 Link current = first; //如果列表为空 if(first == null){ return null; } //浏览列表 while(current.key != key){ //如果它是最后一个节点 if(current.next == null){ return null; }else{ //移动到下一个链接 current = current.next; } } //找到匹配项,更新链接 if(current == first) { //将 first 改为指向 next 链接 first = current.next; }else { //绕过当前链接 current.prev.next = current.next; } if(current == last){ //将最后一个链接改为指向上一个链接 last = current.prev; }else { current.next.prev = current.prev; } return current; } public boolean insertAfter(int key, int newKey, int data){ //从第一个链接开始 Link current = first; //如果列表为空 if(first == null){ return false; } //浏览列表 while(current.key != key){ //如果它是最后一个节点 if(current.next == null){ return false; }else{ //移动到下一个链接 current = current.next; } } Link newLink = new Link(newKey,data); if(current==last) { newLink.next = null; last = newLink; } else { newLink.next = current.next; current.next.prev = newLink; } newLink.prev = current; current.next = newLink; return true; } }
DoublyLinkedListDemo.java
package com.tutorialspoint.list; public class DoublyLinkedListDemo { public static void main(String args[]){ DoublyLinkedList list = new DoublyLinkedList(); list.insertFirst(1, 10); list.insertFirst(2, 20); list.insertFirst(3, 30); list.insertLast(4, 1); list.insertLast(5, 40); list.insertLast(6, 56); System.out.print(" List (First to Last): "); list.displayForward(); System.out.println(""); System.out.print(" List (Last to first): "); list.displayBackward(); System.out.print(" List , after deleting first record: "); list.deleteFirst(); list.displayForward(); System.out.print(" List , after deleting last record: "); list.deleteLast(); list.displayForward(); System.out.print(" List , insert after key(4) : "); list.insertAfter(4,7, 13); list.displayForward(); System.out.print(" List , after delete key(4) : "); list.delete(4); list.displayForward(); } }
如果我们编译并运行上述程序,则会产生以下结果 −
List (First to Last): [ {3,30} {2,20} {1,10} {4,1} {5,40} {6,56} ] List (Last to first): [ {6,56} {5,40} {4,1} {1,10} {2,20} {3,30} ] List (First to Last) after deleting first record: [ {2,20} {1,10} {4,1} {5,40} {6,56} ] List (First to Last) after deleting last record: [ {2,20} {1,10} {4,1} {5,40} ] List (First to Last) insert after key(4) : [ {2,20} {1,10} {4,1} {7,13} {5,40} ] List (First to Last) after delete key(4) : [ {2,20} {1,10} {7,13} {5,40} ]