18天算法基础系列课(三)链表

142 阅读2分钟

链表设计

public class SingleLinkedList<E> extends AbstractList<E> {
   private Node<E> first;
   
   private static class Node<E> {
      E element;
      Node<E> next;
      public Node(E element, Node<E> next) {
         this.element = element;
         this.next = next;
      }
   }

   @Override
   public void clear() {
      size = 0;
      first = null;
   }

   @Override
   public E get(int index) {
      /*
       * 最好:O(1)
       * 最坏:O(n)
       * 平均:O(n)
       */
      return node(index).element;
   }

   @Override
   public E set(int index, E element) {
      /*
       * 最好:O(1)
       * 最坏:O(n)
       * 平均:O(n)
       */
      Node<E> node = node(index);
      E old = node.element;
      node.element = element;
      return old;
   }

   @Override
   public void add(int index, E element) {
      /*
       * 最好:O(1)
       * 最坏:O(n)
       * 平均:O(n)
       */
      rangeCheckForAdd(index);
      
      if (index == 0) {
         first = new Node<>(element, first);
      } else {
         Node<E> prev = node(index - 1);
         prev.next = new Node<>(element, prev.next);
      }
      size++;
   }

   @Override
   public E remove(int index) {
      /*
       * 最好:O(1)
       * 最坏:O(n)
       * 平均:O(n)
       */
      rangeCheck(index);
      
      Node<E> node = first;
      if (index == 0) {
         first = first.next;
      } else {
         Node<E> prev = node(index - 1);
         node = prev.next;
         prev.next = node.next;
      }
      size--;
      return node.element;
   }

   @Override
   public int indexOf(E element) {
      if (element == null) {
         Node<E> node = first;
         for (int i = 0; i < size; i++) {
            if (node.element == null) return i;
            
            node = node.next;
         }
      } else {
         Node<E> node = first;
         for (int i = 0; i < size; i++) {
            if (element.equals(node.element)) return i;
            
            node = node.next;
         }
      }
      return ELEMENT_NOT_FOUND;
   }
   
   /**
    * 获取index位置对应的节点对象
    * @param index
    * @return
    */
   private Node<E> node(int index) {
      rangeCheck(index);
      
      Node<E> node = first;
      for (int i = 0; i < index; i++) {
         node = node.next;
      }
      return node;
   }
}

链表反转

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode curr = head;
        while (curr != null) {
            ListNode next = curr.next;
            curr.next = prev;
            prev = curr;
            curr = next;
        }
        return prev;
    }
}

链表是不是有环

public class Solution {
    public boolean hasCycle(ListNode head) {
        Set<ListNode> seen = new HashSet<ListNode>();
        while (head != null) {
            if (!seen.add(head)) {
                return true;
            }
            head = head.next;
        }
        return false;
    }
}

快慢指针法

public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) {
            return false;
        }
        ListNode slow = head;
        ListNode fast = head.next;
        while (slow != fast) {
            if (fast == null || fast.next == null) {
                return false;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        return true;
    }

双向链表

public class LinkedList<E> extends AbstractList<E> {
   private Node<E> first;
   private Node<E> last;
   
   private static class Node<E> {
      E element;
      Node<E> prev;
      Node<E> next;
      public Node(Node<E> prev, E element, Node<E> next) {
         this.prev = prev;
         this.element = element;
         this.next = next;
      }
   }

   @Override
   public void clear() {
      size = 0;
      first = null;
      last = null;
   }

   @Override
   public E get(int index) {
      return node(index).element;
   }

   @Override
   public E set(int index, E element) {
      Node<E> node = node(index);
      E old = node.element;
      node.element = element;
      return old;
   }

   @Override
   public void add(int index, E element) {
      rangeCheckForAdd(index);

      // size == 0
      // index == 0
      if (index == size) { // 往最后面添加元素
         Node<E> oldLast = last;
         last = new Node<>(oldLast, element, null);
         if (oldLast == null) { // 这是链表添加的第一个元素
            first = last;
         } else {
            oldLast.next = last;
         }
      } else {
         Node<E> next = node(index); 
         Node<E> prev = next.prev; 
         Node<E> node = new Node<>(prev, element, next);
         next.prev = node;
         
         if (prev == null) { // index == 0
            first = node;
         } else {
            prev.next = node;
         }
      }
      
      size++;
   }

   @Override
   public E remove(int index) {
      rangeCheck(index);

      Node<E> node = node(index);
      Node<E> prev = node.prev;
      Node<E> next = node.next;
      
      if (prev == null) { // index == 0
         first = next;
      } else {
         prev.next = next;
      }
      
      if (next == null) { // index == size - 1
         last = prev;
      } else {
         next.prev = prev;
      }
      
      size--;
      return node.element;
   }

   @Override
   public int indexOf(E element) {
      if (element == null) {
         Node<E> node = first;
         for (int i = 0; i < size; i++) {
            if (node.element == null) return i;
            
            node = node.next;
         }
      } else {
         Node<E> node = first;
         for (int i = 0; i < size; i++) {
            if (element.equals(node.element)) return i;
            
            node = node.next;
         }
      }
      return ELEMENT_NOT_FOUND;
   }
   
   /**
    * 获取index位置对应的节点对象
    * @param index
    * @return
    */
   private Node<E> node(int index) {
      rangeCheck(index);
      
      if (index < (size >> 1)) {
         Node<E> node = first;
         for (int i = 0; i < index; i++) {
            node = node.next;
         }
         return node;
      } else {
         Node<E> node = last;
         for (int i = size - 1; i > index; i--) {
            node = node.prev;
         }
         return node;
      }
   }
}

动态数组和双项链表区别,如何选择

动态数组:开辟、销毁内存空间的次数相对较少,但可能造成内存空间浪费(可以通过缩容解决)

◼ 双向链表:开辟、销毁内存空间的次数相对较多,但不会造成内存空间的浪费

◼ 如果频繁在尾部进行添加、删除操作,动态数组、双向链表均可选择

◼ 如果频繁在头部进行添加、删除操作,建议选择使用双向链表

◼ 如果有频繁的(在任意位置)添加、删除操作,建议选择使用双向链表

◼ 如果有频繁的查询操作(随机访问操作),建议选择使用动台数组