使用 Java 的 DSA - 链接列表

链接列表基础知识

链接列表是包含项目的链接序列。每个链接都包含与另一个链接的连接。链接列表是继数组之后第二常用的数据结构。以下是理解链接列表概念的重要术语。

  • 链接 − 链接列表的每个链接都可以存储称为元素的数据。

  • 下一个 − 链接列表的每个链接都包含指向下一个链接的链接,称为下一个。

  • LinkedList − LinkedList 包含指向第一个 Link 的连接链接,称为 First。

Linked List 表示

Linked List

如上图所示,以下是需要考虑的重要点。

  • LinkedList 包含一个名为 first 的链接元素。

  • 每个 Link 都带有一个数据字段和一个称为 next 的链接字段。

  • 每个 Link 都使用其下一个链接与其下一个链接链接。

  • Last Link 带有一个 Link 作为 null 来标记列表的结尾。

Linked List 的类型

以下是各种类型的 Link列表。

  • 简单链接列表 − 项目导航仅向前。

  • 双向链接列表 − 项目可以向前和向后导航。

  • 循环链接列表 − 最后一项包含第一个元素的链接作为下一个,并且第一个元素具有到最后一个元素的链接作为上一个。

基本操作

以下是列表支持的基本操作。

  • 插入 − 在列表开头添加一个元素。

  • 删除 −删除列表开头的一个元素。

  • 显示 − 显示完整列表。

  • 搜索 − 使用给定的键搜索元素。

  • 删除 − 使用给定的键删除元素。

插入操作

插入分为三个步骤:

  1. 使用提供的数据创建新链接。

  2. 将新链接指向旧的第一个链接。

  3. 将第一个链接指向此新链接。

Linked List Insert First
//在第一个位置插入链接
public void insertFirst(int key, int data){
   //创建链接
   Link link = new Link(key,data);
   //将其指向旧的第一个节点
   link.next = first;
   //将 first 指向新的第一个节点
   first = link;
}

删除操作

删除分为两个步骤:

  1. 获取 First Link 指向的链接作为临时链接。

  2. 将 First Link 指向临时链接的下一个链接。

Linked List Delete First
//删除第一项
public Link deleteFirst(){
   //保存对第一个链接的引用
   Link tempLink = first;
   //将第一个链接旁边的标记为第一个
   first = first.next;
   //返回删除的链接
   return tempLink;
}

导航操作

导航是一个递归步骤过程,是搜索、删除等许多操作的基础:

  1. 获取第一个链接指向的链接作为当前链接。

  2. 检查当前链接是否不为空并显示它。

  3. 将当前链接指向当前链接的下一个链接并移动到上一步。

链接列表导航

注意

//显示列表
public void display(){
   //从头开始
   Link current = first;
   //导航到列表末尾
   System.out.print("[ ");
   while(current != null){
      //打印数据
      current.display();
      //移动到下一个项目
      current = current.next;
      System.out.print(" ");
   }
   System.out.print(" ]");
}

高级操作

以下是针对列表指定的高级操作。

  • 排序 − 根据特定顺序对列表进行排序。

  • 反转 − 反转链接列表。

  • 连接 − 连接两个列表。

排序操作

我们使用冒泡排序对列表进行排序。

public void sort(){

   int i, j, k, tempKey, tempData ;
   Link current,next;
   int size = length();
   k = size ;
   for ( i = 0 ; i < size - 1 ; i++, k-- ) {
      current = first ;
      next = first.next ;
      for ( j = 1 ; j < k ; j++ ) {            
         if ( current.data > next.data ) {
            tempData = current.data ;
            current.data = next.data;
            next.data = tempData ;

            tempKey = current.key;
            current.key = next.key;
            next.key = tempKey;
         }
         current = current.next;
         next = next.next;                        
      }
   }
}

反向操作

以下代码演示了如何反转单个链接列表。

public LinkedList reverse() {
    LinkedList reversedlist = new LinkedList();
    Link nextLink = null;
    reverselist.insertFirst(first.key, first.data);
    
    Link currentLink = first;
    // 直到列表中没有更多数据,
    // 在第一个之前插入当前链接并向前移动。
    while(currentLink.next != null){
        nextLink = currentLink.next;
        // 在新列表的开头插入。
        reverselist.insertFirst(nextLink.key, nextLink.data);
        //前进到下一个节点
        currentLink = currentLink.next;
    }
    return reversedlist;
}

连接操作

以下代码演示了反转单个链接列表。

public void concatenate(LinkedList list){
   if(first == null){
      first = list.first;
   }
   if(list.first == null){
      return;
   }
   Link temp = first;
   while(temp.next !=null) {
      temp = temp.next;
   }
   temp.next = list.first;       
}

演示

Link.java
package com.tutorialspoint.list;

public class Link {
   public int key;
   public int data;
   public Link next;

   public Link(int key, int data){
      this.key = key;
      this.data = data;
   }

   public void display(){
      System.out.print("{"+key+","+data+"}");
   }
}
LinkedList.java
package com.tutorialspoint.list;

public class LinkedList {
    //此链接始终指向链接列表中的第一个链接
    //private Link first;
    
    //创建一个空链接列表
    public LinkedList(){
        first = null;
    }

   //在第一个位置插入链接
   public void insertFirst(int key, int data){
      //创建链接
      Link link = new Link(key,data);
      //将其指向旧的第一个节点
      link.next = first;
      //将 first 指向新的第一个节点
      first = link;
   }

   //delete first item
   public Link deleteFirst(){
      //保存对第一个链接的引用
      Link tempLink = first;
      //将第一个链接旁边的标记为第一个
      first = first.next;
      //返回删除的链接
      return tempLink;
   }

   //display the list
   public void display(){
      //从头开始
      Link current = first;
      //导航到列表末尾
      System.out.print("[ ");
      while(current != null){
         //打印数据
         current.display();
         //移动到下一个项目
         current = current.next;
         System.out.print(" ");
      }
      System.out.print(" ]");
   }

   //找到具有给定键的链接
   public Link find(int key){
      //从第一个链接开始
      Link current = first;

      //如果列表为空
      if(first == null){
         return null;
      }
      //浏览列表
      while(current.key != key){
         //如果它是最后一个节点
         if(current.next == null){
            return null;
         }else{
            //转到下一个链接
            current = current.next;
         }
      }      
      //如果找到数据,返回当前链接
      return current;
   }

   //删除指定键的链接
   public Link delete(int key){
      //从第一个链接开始
      Link current = first;
      Link previous = null;
      //如果列表为空
      if(first == null){
         return null;
      }

      //浏览列表
      while(current.key != key){
         //如果它是最后一个节点
         if(current.next == null){
            return null;
         }else{
            //存储对当前链接的引用
            previous = current;
            //移动到下一个链接
            current = current.next;             
         }
      }

      //找到匹配项,更新链接
      if(current == first) {
         //将 first 改为指向 next 链接
         first = first.next;
      }else {
         //绕过当前链接
         previous.next = current.next;
      }    
      return current;
   }


   //列表是否为空
   public boolean isEmpty(){
      return first == null;
   }
   
   public int length(){
      int length = 0;
      for(Link current = first; current!=null;
         current = current.next){
         length++;
      }
      return length;
   }
   
   public void sort(){
      int i, j, k, tempKey, tempData ;
      Link current,next;
      int size = length();
      k = size ;
      for ( i = 0 ; i < size - 1 ; i++, k-- ) {
         current = first ;
         next = first.next ;
         for ( j = 1 ; j < k ; j++ ) {            
            if ( current.data > next.data ) {
               tempData = current.data ;
               current.data = next.data;
               next.data = tempData ;
	 
	           tempKey = current.key;
	           current.key = next.key;
	           next.key = tempKey;
            }
            current = current.next;
           next = next.next;                        
         }
      }
   }

   public LinkedList reverse() { 
      LinkedList reversedlist = new LinkedList();
      Link nextLink = null;     
      reversedlist.insertFirst(first.key, first.data);

      Link currentLink = first;       
      // 直到列表中没有更多数据,
      // 在第一个链接之前插入当前链接并继续前进。
      while(currentLink.next != null){
         nextLink = currentLink.next;           
         // 插入到新列表的开头。
         reversedlist.insertFirst(nextLink.key, nextLink.data); 
         //前进到下一个节点
         currentLink = currentLink.next;            
      }      
      return reversedlist;
   }

   public void concatenate(LinkedList list){
      if(first == null){
         first = list.first;
      }
      if(list.first == null){
         return;
      }
      Link temp = first;

      while(temp.next !=null) {
         temp = temp.next;
      }
      temp.next = list.first;       
   }
}
LinkedListDemo.java
package com.tutorialspoint.list;

public class LinkedListDemo {
   public static void main(String args[]){
      LinkedList list = new LinkedList();
        
      list.insertFirst(1, 10);
      list.insertFirst(2, 20);
      list.insertFirst(3, 30);
      list.insertFirst(4, 1);
      list.insertFirst(5, 40);
      list.insertFirst(6, 56);

      System.out.print("原始列表: ");  
      list.display();
      System.out.println("");
      while(!list.isEmpty()){            
         Link temp = list.deleteFirst();
         System.out.print("删除的值:");  
         temp.display();
         System.out.println("");
      }         
      System.out.print("删除所有项目后的列表: ");          
      list.display();
      System.out.println("");
      list.insertFirst(1, 10);
      list.insertFirst(2, 20);
      list.insertFirst(3, 30);
      list.insertFirst(4, 1);
      list.insertFirst(5, 40);
      list.insertFirst(6, 56);

      System.out.print("Restored List: ");  
      list.display();
      System.out.println("");  

      Link foundLink = list.find(4);
      if(foundLink != null){
        System.out.print("Element found: ");  
         foundLink.display();
         System.out.println("");  
      }else{
         System.out.println("Element not found.");  
      }

      list.delete(4);
      System.out.print("List after deleting an item: ");  
      list.display();
      System.out.println(""); 
      foundLink = list.find(4);
      if(foundLink != null){
         System.out.print("Element found: ");  
         foundLink.display();
         System.out.println("");  
      }else{
         System.out.print("Element not found. {4,1}");  
      }
      System.out.println(""); 
      list.sort();
      System.out.print("List after sorting the data: ");  
      list.display();
      System.out.println(""); 
      System.out.print("Reverse of the list: ");  
      LinkedList list1 = list.reverse();
      list1.display();
      System.out.println(""); 
      
      LinkedList list2 = new LinkedList();

      list2.insertFirst(9, 50);
      list2.insertFirst(8, 40);
      list2.insertFirst(7, 20);

      list.concatenate(list2);
      System.out.print("List after concatenation: ");  
      list.display();
      System.out.println(""); 
   }
}

如果我们编译并运行上述程序,则会产生以下结果:

原始列表: [ {6,56} {5,40} {4,1} {3,30} {2,20} {1,10}  ]
删除的值:{6,56}
删除的值:{5,40}
删除的值:{4,1}
删除的值:{3,30}
删除的值:{2,20}
删除的值:{1,10}
删除所有项目后的列表: [  ]
恢复的列表:[ {6,56} {5,40} {4,1} {3,30} {2,20} {1,10} ]
找到元素:{4,1}
删除项目后的列表:[ {6,56} {5,40} {3,30} {2,20} {1,10} ]
未找到元素。{4,1}
对数据进行排序后的列表:[ {1,10} {2,20} {3,30} {5,40} {6,56} ]
列表的反转:[ {6,56} {5,40} {3,30} {2,20} {1,10} ]
连接后的列表:[ {1,10} {2,20} {3,30} {5,40} {6,56} {7,20} {8,40} {9,50} ]