LinkList详解

:在学习LinkList之前可以先去看一下我的另一篇博客单链表的定义及其模拟实现——java https://editor.csdn.net/md/?articleId=130642627,有助于本博客的理解

ArrayList和LinkedList的区别

在这里插入图片描述

LinkList模拟实现

在这里插入图片描述
定义三个类:MyLinkList用于LinkList成员变量和成员方法的定义、Test用于测试、ListIndexOutException用于定义越界异常

ListIndexOutException类

public class ListIndexOutOfException extends RuntimeException {
    public ListIndexOutOfException() {
    }
}

MyLinkList类

public class MyLinkList {
    
    static class ListNode {
        public int val;
        public ListNode prev;
        public ListNode next;

        public ListNode(int val) {
            this.val = val;
        }
    }

    //头结点
    public ListNode head;
    //尾结点
    public ListNode last;

    //头插法
    public void addFirst(int data) {
        ListNode node = new ListNode(data);

        if (head == null) {
            head = node;
            last = node;
        } else {
            node.next = head;
            head.prev = node;
            head = node;
        }

    }

    //尾插法
    public void addLast(int data) {
        ListNode node = new ListNode(data);
        if (head == null) {
            last = node;
            head = node;
        } else {
            last.next = node;
            node.prev = last;
            last = last.next;
        }

    }

    //返回某个下标的结点
    public ListNode findIndex(int index) {
        ListNode cur = head;
        while (index != 0) {
            cur = cur.next;
            index--;
        }
        return cur;
    }

    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index, int data) {
        if (index < 0 || index > this.size()) {
            throw new ListIndexOutOfException();
        }
        if (index == 0) {
            addFirst(data);
            return;
        }
        if (index == size()) {
            addLast(data);
            return;
        }
        ListNode node = new ListNode(data);
        ListNode cur = findIndex(index);
        cur.prev.next = node;
        node.prev = cur.prev;
        node.next = cur;
        cur.prev = node;
    }

    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key) {
        ListNode cur = this.head;
        while (cur != null) {
            if (cur.val == key) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

    //删除第一次出现关键字为key的节点
    public void remove(int key) {
        ListNode cur = head;
        while (cur != null) {
            if (cur.val == key) {
                if (cur == head) {
                    head = head.next;
                    return;
                }
                cur.prev.next = cur.next;
                if (cur == last) {
                    last = last.prev;
                    return;
                }
                cur.next.prev = cur.prev;
                return;
            }
            cur = cur.next;
        }
    }

    //删除所有值为key的节点
    public void removeAllKey(int key) {
        ListNode tmp = head;
        while (tmp != null) {
            remove(key);
            tmp = tmp.next;
        }

    }

    //得到单链表的长度
    public int size() {
        ListNode cur = this.head;
        int length = 0;
        while (cur != null) {
            cur = cur.next;
            length++;
        }
        return length;
    }

    //遍历打印
    public void display() {
        ListNode cur = this.head;
        while (cur != null) {
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
        System.out.println();
    }

    public void clear() {
        ListNode cur = head;
        while (cur != null) {
            ListNode curNext = cur.next;
            cur.prev = null;
            cur.next = null;
            cur = curNext;
        }
        head = null;
        last = null;
    }
}

Test类

public class Test {
    public static void main(String[] args) {
        //尾插法测试
        MyLinkList myLinkList2 = new MyLinkList();
        myLinkList2.addLast(1);
        myLinkList2.addLast(2);
        myLinkList2.addLast(3);
        myLinkList2.addLast(4);
        myLinkList2.display();

        //头插法测试
        MyLinkList myLinkList1 = new MyLinkList();
        myLinkList1.addFirst(1);
        myLinkList1.addFirst(2);
        myLinkList1.addFirst(3);
        myLinkList1.addFirst(4);
        myLinkList1.display();

        //addIndex测试
        System.out.println("addIndex测试");
        myLinkList1.addIndex(0, 5);
        myLinkList1.display();
        myLinkList1.addIndex(5, 0);
        myLinkList1.display();
        myLinkList1.addIndex(3, 99);
        myLinkList1.display();

        //remove测试
        System.out.println("remove测试");
        myLinkList1.remove(5);
        myLinkList1.display();
        myLinkList1.remove(0);
        myLinkList1.display();
        myLinkList1.remove(99);
        myLinkList1.display();

        //emoveAllKey测试
        System.out.println("removeAllKey测试");
        myLinkList1.addFirst(4);
        myLinkList1.addLast(1);
        myLinkList1.addIndex(1, 2);
        myLinkList1.display();
        myLinkList1.removeAllKey(4);
        myLinkList1.display();
        myLinkList1.removeAllKey(1);
        myLinkList1.display();
        myLinkList1.removeAllKey(2);
        myLinkList1.display();
    }
}

测试结果

在这里插入图片描述

java原生LinkedList详解

实际上在IDEA,JDK环境下的LinkList底层就是一个双向链表,由于链表没有将元素存储在连续的空间中,元素存储在单独的节点中,然后通过引用将节点连接起来了,因此在在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。
在这里插入图片描述在集合框架中,LinkedList也实现了List接口
在这里插入图片描述

原生的LinkedList的继承和实现接口如下
在这里插入图片描述

LinkedList的特点

  1. LinkedList实现了List接口
  2. LinkedList的底层使用了双向链表
  3. LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问
  4. LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)
  5. LinkedList比较适合任意位置插入的场景

LinkList的使用

构造函数
 public LinkedList() {
    }

    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param  c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }

无参构造函数没有什么需要说明的.
重点看public LinkedList(Collection<? extends E> c)这个有参的构造函数
先来解释一下这句代码 首先这个构造方法的形参整体的类型是一个Collection<? extends E>类型,形参名是c。Collection<? extends E>类型表明该类型必须是实现了Collection(可以理解为集合的意思)接口的一个类(换句话说就是这个类必须是一个集合),所以从下图中可以得知ArrayList、LinkedList、Vetor等都是可以的。
在这里插入图片描述此外,<? extends E>表明这个集合里面的元素类型是一个泛型,比如是String、Integer、Float等,而且这个泛型是E类型或者E的子类都是可以的,比如可以为Integer,也可以是int。?是通配符。
而整个带参数的构造函数的作用就是将集合c中的所有?类型的元素复制一份作为新的LinkedList类型集合的元素

实例

import java.util.ArrayList;
import java.util.LinkedList;
public class main {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<String>();
        arrayList.add("hello");
        System.out.println(arrayList);
        LinkedList<String>  linkedList = new LinkedList<String>(arrayList);//arrList实现了Conection接口,并且泛型为String ,符合是String或者String子类的要求,而这个带参数的构造函数的作用就将arraylist里面的的元素内容全部复制到linkedList里面来,创建一个新的linkedList对象
        linkedList.add("bai xian");
        System.out.println(linkedList);
        LinkedList<String> linkedList1 = new LinkedList<>(linkedList);
        System.out.println(linkedList1);
    }
}

在这里插入图片描述

public class main {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<String>();
        arrayList.add("hello");
        System.out.println(arrayList);
        LinkedList<Integer>  linkedList = new LinkedList<Integer>(arrayList);//这样就报错了。因为String不是Integer的子类
    }
}

在这里插入图片描述

LinkedList的其他常用方法介绍

在这里插入图片描述
就不一一列举了,有兴趣的可以去看我的另一篇博客LinkList的模拟实现,那里面模拟实现了上述的所有方法。这里给个实例。

实例

public class main {
    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        list.add(1); // add(elem): 表示尾插
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        list.add(7);
        System.out.println(list.size());
        System.out.println(list);
// 在起始位置插入0
        list.add(0, 0); // add(index, elem): 在index位置插入元素elem
        System.out.println(list);
        list.remove(); // remove(): 删除第一个元素,内部调用的是removeFirst()
        list.removeFirst(); // removeFirst(): 删除第一个元素
        list.removeLast(); // removeLast(): 删除最后元素
        list.remove(1); // remove(index): 删除index位置的元素
        System.out.println(list);
// contains(elem): 检测elem元素是否存在,如果存在返回true,否则返回false
        if(!list.contains(1)){
            list.add(0, 1);
        }

        list.add(1);
        System.out.println(list);
        System.out.println(list.indexOf(1)); // indexOf(elem): 从前往后找到第一个elem的位置,返回下标
        System.out.println(list.lastIndexOf(1)); // lastIndexOf(elem): 从后往前找第一个1的位置。返回下标
        int elem = list.get(0); // get(index): 获取指定位置元素
        list.set(0, 100); // set(index, elem): 将index位置的元素设置为elem
        System.out.println(list);
// subList(from, to): 用list中[from, to)之间的元素构造一个新的LinkedList返回
        List<Integer> copy = list.subList(0, 3);
        System.out.println(list);
        System.out.println(copy);
        list.clear(); // 将list中元素清空
        System.out.println(list.size());
    }
}

在这里插入图片描述

LinkedList的遍历

LinkList遍历主要有三种方式,一种是用for—each遍历,一种最常见的用while循环遍历,还有一种使用跌迭代器遍历

实例

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
public class main {
    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        list.add(1); // add(elem): 表示尾插
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        list.add(7);
        System.out.println(list.size());
// foreach遍历
        for (int e:list) {
            System.out.print(e + " ");
        }
        System.out.println();
// 使用迭代器遍历---正向遍历
        ListIterator <Integer> it = list.listIterator();
        while(it.hasNext()){
            System.out.print(it.next()+ " ");
        }
        System.out.println();
// 使用反向迭代器---反向遍历
        ListIterator<Integer> rit = list.listIterator(list.size());
        while (rit.hasPrevious()){
            System.out.print(rit.previous() +" ");
        }
        System.out.println();
    }
}

在这里插入图片描述
至此LinkList的学习就告一段落了。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐