链表

124 阅读3分钟

基本概念

链表和数组一样是线性表(Liner List)结构,它并不需要一块连续的内存空间, 他通过指针将一块零散的内存块串联起来使用。三种常见的链表结构,分别是:单链表、双向链表和循环链表

链表的基本元素是结点,往往通过一个类实现一个结点,每个链表的结点需要存储数据和记录链上下一个结点的地址(data and next)。第一个结点叫做头结点,最后一个结点叫做尾结点,其中头结点记录链表的基地址,然后就可以遍历得到整条链表,而尾结点指向一个空地址NULL表示链表上最后一个结点。

NOTE:链表中涉及到指针的操作,切记一个地址可以被多个指针指向。注重指针指向断开的顺序。

特点

因为链表不需要连续的内存空间,所以简单的删除和插入操作时间复杂度是O(1),而随机访问需要遍历链表,时间复杂度为O(n)。

源码分析

 /*******************************************************
 *
 *  The Node class
 *
 ********************************************************/
   private static class Node<AnyType>
   {
      // "泛型data存储数据,next记录下一个结点的地址"
      private AnyType data;
      private Node<AnyType> next;
      // "初始化方法"
      public Node(AnyType data, Node<AnyType> next)
      {
         this.data = data;
         this.next = next;
      }
   }
   
   public class LinkedList<AnyType> implements Iterable<AnyType>
   {
       private Node<AnyType> head;
    
     /**
       *  Constructs an empty list
       *  "一个空链表,头指针为空(基地址)即可"
       */
       public LinkedList()
       {
          head = null;
       }
       /**
       *  Returns true if the list is empty
       *
       */
       public boolean isEmpty()
       {
          return head == null;
       }
     /**
       *  Inserts a new node at the beginning of this list.
       *  "插入一个新结点到表头"
       */
       public void addFirst(AnyType item)
       {
          "新建一个结点,next指向上一个头结点,然后head指向此新头结点"
          head = new Node<AnyType>(item, head);
       }
       
     /**
       *  Returns the first element in the list.
       *
       */
       public AnyType getFirst()
       {
          if(head == null) throw new NoSuchElementException();
          return head.data;
       }
       
     /**
       *  Removes the first element in the list.
       *
       */
       public AnyType removeFirst()
       {
          AnyType tmp = getFirst();
          "head指向下一个结点,相当于移除头结点"
          head = head.next;
          return tmp;
       }
       
     /**
       *  Inserts a new node to the end of this list.
       *
       */
       public void addLast(AnyType item)
       {
          "首先判断头结点是不是为空,相当于添加头结点"
          if( head == null)
             addFirst(item);
          else
          {
            "如果链表不为空,需要根据头结点head遍历到尾结点"
             Node<AnyType> tmp = head;
             while(tmp.next != null) tmp = tmp.next;
            "此前的尾结点指向一个指向null的结点,完成添加结点到尾部"
             tmp.next = new Node<AnyType>(item, null);
          }
       }
       
     /**
       *  Returns the last element in the list.
       *
       */
       public AnyType getLast()
       {
          if(head == null) throw new NoSuchElementException();
    
          Node<AnyType> tmp = head;
          while(tmp.next != null) tmp = tmp.next;
    
          return tmp.data;
       }
       
        /**
       *  Removes all nodes from the list.
       *
       */
       public void clear()
       {
       "只需要头结点为空即可"
          head = null;
       }
       
       /**
       *  Returns the data at the specified position in the list.
       *  "根据位置索引查看链表中的元素"
       */
       public AnyType get(int pos)
       {
          if (head == null) throw new IndexOutOfBoundsException();
    
          Node<AnyType> tmp = head;
          "相当于执行遍历的次数"
          for (int k = 0; k < pos; k++) tmp = tmp.next;
    
          if( tmp == null) throw new IndexOutOfBoundsException();
    
          return tmp.data;
       }
       
     /**
       *  Inserts a new node after a node containing the key.
       *  "在指定元素的后面插入新的结点"
       */
       public void insertAfter(AnyType key, AnyType toInsert)
       {
          Node<AnyType> tmp = head;
    
          while(tmp != null && !tmp.data.equals(key)) tmp = tmp.next;
            
          if(tmp != null)
          "先创建一个node结点(指向下一个结点tmp.next),然后再断开tmp原来的指向,指向新的节点node"
             tmp.next = new Node<AnyType>(toInsert, tmp.next);
       }
       
       /**
       *  Inserts a new node before a node containing the key.
       * "在指定元素的前面插入新的结点"
       */
       public void insertBefore(AnyType key, AnyType toInsert)
       {
          if(head == null) return;
    
          if(head.data.equals(key))
          {
             addFirst(toInsert);
             return;
          }
    
          Node<AnyType> prev = null;
          Node<AnyType> cur = head;
          "在指定元素的前面插入新的结点,换一种思路就是,找到指点元素的前一个节点,然后在前一个节点后插入一个结点即可"
          while(cur != null && !cur.data.equals(key))
          {
             prev = cur;
             cur = cur.next;
          }
          //insert between cur and prev
          if(cur != null)
             prev.next = new Node<AnyType>(toInsert, cur);
       }
       
     /**
       *  Removes the first occurrence of the specified element in this list.
       *
       */
       public void remove(AnyType key)
       {
          if(head == null)
             throw new RuntimeException("cannot delete");
    
          if( head.data.equals(key) )
          {
             head = head.next;
             return;
          }
    
          Node<AnyType> cur  = head;
          Node<AnyType> prev = null;
    
          while(cur != null && !cur.data.equals(key) )
          {
             prev = cur;
             cur = cur.next;
          }
    
          if(cur == null)
             throw new RuntimeException("cannot delete");
    
          //delete cur node
          prev.next = cur.next;
       }
       
       /**
       *  Reverses the list
       *  Complewxity: O(n) "反转链表"
       */
       public LinkedList<AnyType> reverse()
       {
          LinkedList<AnyType> list = new LinkedList<AnyType>();
          Node<AnyType> tmp = head;
          while(tmp != null)
          {
             list.addFirst( tmp.data );
             tmp = tmp.next;
          }
          return list;
       }