zoukankan      html  css  js  c++  java
  • 04 链表(LinkedList)

      链表是真正的动态数据结构,其数据存储在“结点(Node)”中,它不需要处理固定容量的问题。其缺点在于丧失了随机访问的能力,不支持快速查询,而数组是支持快速查询的。

    1.链表接口的实现

      1 /**
      2  * @author 阿遠
      3  * Date: 2019/1/15
      4  * Time: 11:08
      5  */
      6 public class LinkedList<E> {
      7 
      8 
      9     private Node dummyhead; // 链表头
     10     private int size; // 链表容量
     11     private class Node{
     12         public E e;  // 元素
     13         public Node next;   // 结点
     14 
     15         private Node(E e, Node next) {
     16             this.e = e;
     17             this.next = next;
     18         }
     19 
     20         public Node(E e) {
     21             this(e, null);
     22         }
     23 
     24         public Node() {
     25             this(null, null);
     26         }
     27 
     28         @Override
     29         public String toString() {
     30             return e.toString();
     31         }
     32     }
     33 
     34     public LinkedList() {
     35         dummyhead = new Node(null, null);
     36         size = 0;
     37     }
     38 
     39     // 获取列表中的元素个数
     40     public int getSize() {
     41         return size;
     42     }
     43 
     44     // 返回链表是否为空
     45     public boolean isEmpty() {
     46         return size == 0;
     47     }
     48 
     49     //在链表的index(0-based)位置添加新的元素e
     50     public void add(int index, E e) {
     51         if (index < 0 || index > size) {
     52             throw new IllegalArgumentException("Add failed.Illegal index.");
     53         }
     54         Node pre = dummyhead;
     55         for (int i = 0; i < index; i ++) {
     56             pre = pre.next;
     57         }
     58 //            Node node = new Node(e);
     59 //            node.next = pre.next;
     60 //            pre.next = node;
     61         pre.next = new Node(e, pre.next);
     62         size ++;
     63     }
     64     //在链表头添加新的元素
     65     public void addFirst(E e) {
     66         add(0, e);
     67     }
     68     // 在链表的末尾添加新的元素
     69     public void addLast(E e) {
     70         add(size, e);
     71     }
     72 
     73     // 获得链表的第index个位置的元素
     74     public E get(int index) {
     75         if (index < 0 || index >= size)
     76             throw new IllegalArgumentException("Get failed.Illegal index.");
     77         Node cur = dummyhead.next;
     78         for (int i = 0; i < index; i++) {
     79             cur = cur.next; // 遍历找到index处的Node
     80         }
     81         return cur.e;
     82     }
     83     // 获得列表的第一个元素
     84     public E getFirst() {
     85         return get(0);
     86     }
     87     // 获得链表中最后一个元素
     88     public E getLast() {
     89         return get(size - 1);
     90     }
     91 
     92     // 修改列表中第index个位置的元素为e
     93     public void set(int index, E e) {
     94         if (index < 0 || index >= size)
     95             throw new IllegalArgumentException("Update failed.Illegal index.");
     96         Node cur = dummyhead.next;
     97         for (int i = 0; i < index; i++) {
     98             cur = cur.next;
     99         }
    100         cur.e = e;
    101     }
    102 
    103     // 查找链表中是否有元素e
    104     public boolean contains(E e) {
    105         Node cur = dummyhead.next;
    106         while(cur != null) {
    107             if (cur.e.equals(e)) {
    108                 return true;
    109             }
    110             cur = cur.next;
    111         }
    112         return false;
    113     }
    114     // 从列表中删除index位置处的元素,返回删除的元素
    115     public E remove(int index) {
    116         if (index < 0 || index >= size)
    117             throw new IllegalArgumentException("Remove failed.Illegal index.");
    118         Node prev = dummyhead;
    119         for (int i = 0; i < index; i ++) {
    120             prev = prev.next;
    121         }
    122         Node retNode = prev.next;
    123         prev.next = retNode.next;
    124         retNode.next = null;
    125         size --;
    126 
    127         return retNode.e;
    128     }
    129     // 从链表中删除第一个元素,返回删除的元素
    130     public E removeFirst() {
    131         return remove(0);
    132     }
    133     // 从链表中删除最后一个元素
    134     public E removeLast() {
    135         return remove(size - 1);
    136     }
    137 
    138     @Override
    139     public String toString() {
    140         StringBuilder res = new StringBuilder();
    141 //        Node cur = dummyhead.next;
    142 //        while(cur != null) {
    143 //            res.append(cur + "->");
    144 //            cur = cur.next;
    145 //        }
    146         for (Node cur = dummyhead.next; cur != null; cur = cur.next)
    147             res.append(cur + "->");
    148         res.append("NULL");
    149         return res.toString();
    150     }
    151 }

    2. 链表接口的测试

     1 public class Main {
     2 
     3     public static void main(String[] args) {
     4 
     5         LinkedList<Integer> linkedList = new LinkedList<Integer>();
     6         for (int i = 0; i < 5; i ++) {
     7             linkedList.addFirst(i);
     8             System.out.println(linkedList);
     9         }
    10         System.out.println("在索引为2的位置插入元素: 666");
    11         linkedList.add(2, 666);
    12         System.out.println(linkedList);
    13 
    14         System.out.println("移除索引为2的位置的元素: 666");
    15         linkedList.remove(2);
    16         System.out.println(linkedList);
    17 
    18         System.out.println("移除链表头的元素:4");
    19         linkedList.removeFirst();
    20         System.out.println(linkedList);
    21 
    22         System.out.println("移除链表尾的元素:0");
    23         linkedList.removeLast();
    24         System.out.println(linkedList);
    25     }
    26 }

      测试结果:

    0->NULL
    1->0->NULL
    2->1->0->NULL
    3->2->1->0->NULL
    4->3->2->1->0->NULL
    在索引为2的位置插入元素: 666
    4->3->666->2->1->0->NULL
    移除索引为2的位置的元素: 666
    4->3->2->1->0->NULL
    移除链表头的元素:4
    3->2->1->0->NULL
    移除链表尾的元素:0
    3->2->1->NULL

    3.链表的复杂度分析

    添加操作
        addLast(e)          O(n)     //从链表头开始遍历
        addFirst(e)         O(1)
        add(index, e)       O(n/2) = O(n)      //从链表头开始遍历
        删除操作
        removeLast(e)       O(n)    //从链表头开始遍历
        removeFirst(e)      O(1)
        remove(index, e)    O(n/2) = O(n)      //从链表头开始遍历
        修改操作
        set(index)          O(n)
        contains(e)         O(n)
        总结:
        增 : O(n)     删 : O(n)    改 : O(n)    查 : O(n)
        适合只操作链表头:O(1)

     4.链表的实例(LeetCode)

      移除链表元素

      题目:

      删除链表中等于给定值 val 的所有节点。

      示例:

      输入: 1->2->6->3->4->5->6, val = 6
      输出: 1->2->3->4->5
      
      答案:
     1 /**
     2  * @author 阿遠
     3  * Date: 2019/1/21
     4  * Time: 11:01
     5  */
     6 //public class ListNode {
     7 //    int val;
     8 //    ListNode next;
     9 //    ListNode(int x) { val = x; }
    10 //}
    11 public class Solution {
    12     public ListNode removeElements(ListNode head, int val) {
    13         // 传入的链表不为空,链表头就是val以及新的链表头又是val
    14         while (head != null && head.val == val) {
    15 //            ListNode delNode = head;
    16 //            head = head.next;
    17 //            delNode.next = null;
    18             head = head.next;
    19         }
    20         //如果链表中所有的结点都是相同的val,此时就已经全部删除,链表为空
    21         if (head == null)
    22             return null;
    23         // 链表中间的部分删除
    24         ListNode pre = head;
    25         while (pre.next != null) {
    26             if (pre.next.val == val) {
    27 //                ListNode delNode = pre.next;
    28 //                pre.next = delNode.next;
    29 //                delNode.next = null;
    30                 pre.next = pre.next.next;
    31             } else {
    32                 pre = pre.next;
    33             }
    34         }
    35         return head;
    36     }
    37 }
  • 相关阅读:
    Winform学习笔记
    ASP.NET后台注册javascript脚本方法
    使用MultipleActiveResultSets复用Sql Server 2008数据库连接
    angular 2 新建组件命令
    一个关于日志操作方法
    vs2017 打开包管理器 (程序包管理控制台)
    Asp.Net Core Identity 怎么获取当前登录的用户信息?
    abp 实现所有审计的接口
    IIS8.5 布署 Asp.Net Core 老是报500的错误怎么办?
    .NET Core 1.1布署后出现“HTTP Error 502.5 Process Failure”的解决办法
  • 原文地址:https://www.cnblogs.com/a-yuan/p/10287724.html
Copyright © 2011-2022 走看看