使用 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}  ]