Java路径-34-Java的LinkedList(java里面linkedlist)

createh54个月前 (12-30)技术教程47

1 LinkedList的概念

LinkedList本质上是一个双向链表。

那么什么是链表呢?链表原先是C/C++的概念,是一种线性的存储结构,意思是将要存储的数据存在一个存储单元里面,这个存储单元里面除了存放有待存储的数据以外,还存储有其下一个存储单元的地址(下一个存储单元的地址是必要的,有些存储结构还存放有其前一个存储单元的地址),每次查找数据的时候,通过某个存储单元中的下一个存储单元的地址寻找其后面的那个存储单元。

而LinkedList是双向链表,在list中的每个元素,在存储自身元素外,还额外存储了其前一个和后一个元素的地址,所以 也就可以很方便地根据当前元素获取到其前后的元素。链表的尾部元素的后一个节点是链表的头节点;而链表的头结点前一个节点则是则是链表的尾节点。

由于LinkedList的底层是双向链表,因此其顺序访问的效率非常高,而随机访问的效率就比较低了,因为通过索引去访问的时候,首先会比较索引值和链表长度的1/2,若前者大,则从链表尾开始寻找,否则从链表头开始寻找,这样就把双向链表与索引值联系起来了。



2 LinkedList的定义

根据LinkedList的声明代码,可以看到它除了实现List接口外,还实现了Deque接口,而Deque主要是一个双端队列,因此LinkedList除了可以作为List使用外,还可以当做队列使用。 ?

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

3 LinkedList的使用

(1)LinkedList的构造

// 1.无参构造       
LinkedList()
//2.使用其他集合容器中的元素构造List      
public LinkedList(Collection<? extends E> c)

代码如下:

public static void main(String[] args) {
    // 构造一个空的LinkedList
    List<Integer> list1 = new LinkedList<>();
    List<String> list2 = new java.util.ArrayList<>();
    list2.add("JavaSE");
    list2.add("JavaWeb");
    list2.add("JavaEE");
    // 使用ArrayList构造LinkedList
    List<String> list3 = new LinkedList<>(list2);
}

(2)LinkedList的其他常用方法介绍

boolean add(E e)    //尾插e

void add(int index,E element)   //将e插入到index位置

boolean addAll(Collection<? extends E> c)   //尾插c中的元素

E remove(int index) //删除Index位置的元素

boolean remove(Object o)    //删除遇到的第一个o

E get(int index)    //获取下标index位置的元素

E set(int index,E element)  //将下标为index位置的元素设置为element

void clear()    //清空

boolean contains(Object o)  //判断o是否在线性表中

int indexOf(Object o)   //返回第一个o所在下标

int lastIndexOf(Object o)   //返回最后一个o所在下标

List<E>subList(int fromIndex,int toIndex)   //截取部分list

代码如下:

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());
}

(3) LinkedList的遍历

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();
}

(4)LinkedList的模拟实现

代码如下:

public class MyLinkedList {
    static class LinkedList {
        public int val;
        public LinkedList prev;
        public LinkedList next;
        public LinkedList(int val) {
            this.val = val;
        }

    }
        public LinkedList head;
        public LinkedList last;
    // 2、无头双向链表实现
        //头插法
        public void addFirst(int data){
            LinkedList node = new LinkedList(data);
            if(head==null) {
                head = node;
                last = node;
            } else {
                head.prev = node;
                node.next = head;
                head = node;
            }
        }
        //尾插法
        public void addLast(int data){
            LinkedList node = new LinkedList(data);
            if(head==null) {
                head=node;
                last=node;
            } else {
                last.next=node;
                node.prev=last;
                last = node;
            }

        }
        //任意位置插入,第一个数据节点为0号下标
        public void addIndex(int index,int data){
            if(index<0 || index>size()) {
                System.out.println("位置不合法");
            }
            if(index==0) {
                addLast(data);
                return;
            }
            if(index==size()) {
                addLast(data);
                return;
            }

            LinkedList node = new LinkedList(data);
            LinkedList cur = findIndex(index);
            node.next = cur;
            cur.prev.next = node;
            node.prev = cur.prev;
            cur.prev=node;
        }

        public LinkedList findIndex(int index) {
            LinkedList cur = head;
            while (index!=0) {
                cur = cur.next;
                index--;
            }
            return cur;
        }
        //查找是否包含关键字key是否在链表当中
        public boolean contains(int key){
            LinkedList cur = head;
            while (cur!=null) {
                if(cur.val==key) {
                    return true;
                }
                cur = cur.next;
            }
            return false;
        }
        //删除第一次出现关键字为key的节点
        public void remove(int key){
            LinkedList cur = head;
            while (cur!=null) {
                if(cur.val==key) {
                    //头节点
                    if(cur==head) {
                        head = head.next;
                        if (head!=null) {
                            head.prev = null;
                        }
                    } else {
                        //中间 节点和 尾部节点
                        cur.prev.next = cur.next;
                        if(cur.next!=null) {
                            //中间
                            cur.next.prev = cur.prev;
                        }else {
                            //尾部
                            last = last.prev;
                        }
                    }
                    return;
                }
                cur=cur.next;
            }
        }
        //删除所有值为key的节点
        public void removeAllKey(int key){
            LinkedList cur = head;
            while (cur!=null) {
                if(cur.val==key) {
                    //头节点
                    if(cur==head) {
                        head = head.next;
                        if (head!=null) {
                            head.prev = null;
                        }
                    } else {
                        //中间 节点和 尾部节点
                        cur.prev.next = cur.next;
                        if(cur.next!=null) {
                            //中间
                            cur.next.prev = cur.prev;
                        }else {
                            //尾部
                            last = last.prev;
                        }
                    }
                }
                cur=cur.next;
            }
        }
        //得到的长度
        public int size(){
            int len = 0;
            LinkedList cur = head;
            while (cur!=null) {
                len++;
                cur=cur.next;
            }
            return len;
        }
        public void display(){
            LinkedList cur = head;
            while (cur!=null) {
                System.out.print(cur.val+" ");
                cur=cur.next;
            }
            System.out.println();
        }
        public void clear(){
            LinkedList cur = head;
            while (cur!=null) {
                LinkedList curNext = cur.next;
                cur.prev = null;
                cur.next = null;
                cur = curNext;
            }
            head=null;;
            last=null;
        }

}

3 常用的方法

方法

说明

public boolean add(E e)

链表末尾添加元素,返回是否成功,成功为 true,失败为 false。

public void add(int index, E element)

向指定位置插入元素。

public boolean addAll(Collection c)

将一个集合的所有元素添加到链表后面,返回是否成功,成功为 true,失败为 false。

public boolean addAll(int index, Collection c)

将一个集合的所有元素添加到链表的指定位置后面,返回是否成功,成功为 true,失败为 false。

public void addFirst(E e)

元素添加到头部。

public void addLast(E e)

元素添加到尾部。

public boolean offer(E e)

向链表末尾添加元素,返回是否成功,成功为 true,失败为 false。

public boolean offerFirst(E e)

头部插入元素,返回是否成功,成功为 true,失败为 false。

public boolean offerLast(E e)

尾部插入元素,返回是否成功,成功为 true,失败为 false。

public void clear()

清空链表。

public E removeFirst()

删除并返回第一个元素。

public E removeLast()

删除并返回最后一个元素。

public boolean remove(Object o)

删除某一元素,返回是否成功,成功为 true,失败为 false。

public E remove(int index)

删除指定位置的元素。

public E poll()

删除并返回第一个元素。

public E remove()

删除并返回第一个元素。

public boolean contains(Object o)

判断是否含有某一元素。

public E get(int index)

返回指定位置的元素。

public E getFirst()

返回第一个元素。

public E getLast()

返回最后一个元素。

public int indexOf(Object o)

查找指定元素从前往后第一次出现的索引。

public int lastIndexOf(Object o)

查找指定元素最后一次出现的索引。

public E peek()

返回第一个元素。

public E element()

返回第一个元素。

public E peekFirst()

返回头部元素。

public E peekLast()

返回尾部元素。

public E set(int index, E element)

设置指定位置的元素。

public Object clone()

克隆该列表。

public Iterator descendingIterator()

返回倒序迭代器。

public int size()

返回链表元素个数。

public ListIterator listIterator(int index)

返回从指定位置开始到末尾的迭代器。

public Object[] toArray()

返回一个由链表元素组成的数组。

public T[] toArray(T[] a)

返回一个由链表元素转换类型而成的数组。

4 ArrayList和LinkedList的区别

  • 在存储空间上,ArrayList在物理上一定连续,LinkedList在逻辑上连续,但物理上不一定连续
  • ArrayList支持随机访问,时间复杂度为O(1),但是LinkedList不支持,时间复杂度为O(N)
  • ArrayList在头插时需要搬移元素,效率低O(N),LinkedList只需要修改引用的指向,时间复杂度为O(1)
  • ArrayList在插入时空间不够时需要扩容,但是LinkedList没有容量的概念
  • ArrayList应用于“元素高效存储和频繁访问”,LinkedList应用于“任意位置插入和删除频繁”

相关文章

几种获取resources目录下的文件方式

前言一般我们的配置信息默认都是会配置在/src/main/resources/application.properties(或者application.yml)文件中,当然,也可以在resources...

我的世界启动器Java路径如何设置(我的世界官方启动器java路径)

这次搞趣网小编为诸位我的世界PC端玩家带来的是我的世界启动器Java路径如何设置攻略,希望诸位我的世界玩家会喜欢。我的世界java路径设置攻略:1、首先我们要确保电脑中已经下载并安装好了最新的java...

java从jar包中读取资源文件(读取jar包内文件)

由于特别情况,我们通常需要读取jar中的资源;本文只要记录读取资源并通过jar方式运行和在开发IDE中运行的一致性。常规使用#常规使用 - 绝对路径常规使用 - 项目的相对路径取的是当前项目的根目录下...

JAVA中的文件操作3-如何查找文件(java查找文件夹)

JAVA中的文件操作3-如何查找文件在前面的JAVA中的文件操作1-如何获取文件信息,创建文件和JAVA中的文件操作2-如何读写文件中,我们介绍了文件的基本操作。那么,我们有时候还可能会遇到从文件夹中...

Java遍历目录文件,一个while循环即可

直奔主题,看代码实现public static void main(String[] args) { File dir = new File("/home/user"); /...

java 代码里读取jar包下resources目录下的文件

简述java项目里,我们时常需要读取一些自定义的文件,我们一般也会把这些文件放在resources目录下,但有时候,我们在idea开发时明明是可以读取到文件的,一打包放到Linux或者Tomcat上运...