LinkedList (概念、使用,遍历,以及与ArrayList的区别)

**List 的实现类之二--------LinkedList **

当在 ArrayList 任意位置进行插入或者删除元素时,需要将后序元素整体往前或往后搬移,时间复杂度为O(n),效率比较低,因此:Java 集合中又引入了另一种结构 :LinkedList,即链表结构;

LinkedList 介绍

LinkedList 是一个普通的类,底层采用链表结构,它继承自 AbstractList, 实现了 ListDequeCloneableSerializable 等接口;

LinkedList 使用

LinkedList 的 2 种构造方式

由于底层结构是链表,所以没有容量一说,因此构造方式 比 ArrayList 少一个;

  • 无参构造 LinkedList()
 List<Integer> list1=new LinkedList<>();
  • 利用其他 Collection 中的元素构造: public LinkedList(Collection<? extends E> c)
 List<String> al = new ArrayList<>();
        al.add("111");
        al.add("222");
       //使用其他容器构造
       List<String> list1=new LinkedList<>(al);
       System.out.println(list1); //[111, 222]

LinkedList 的常见方法

(1) public boolean add(E e): 尾部插入元素 e

 List<String> list=new LinkedList();
       list.add("0000");
       list.add("1111");
     System.out.println(list);  //[0000, 1111]

(2) public void add(int index, E e): 在index 位置插入e

 List<String> list=new LinkedList();
     list.add("0000");
     list.add("1111");
     list.add(0,"5555");
     System.out.println(list); //[5555, 0000, 1111]

(3) public boolean addAll(Collection<? extends E> c):尾部插入 c 中的元素

//将list中的所有元素插入到list1中
   List<String> list=new LinkedList();
        list.add("0000");
        list.add("1111");
        List<String> list1=new LinkedList<>();
        list1.addAll(list);  
        System.out.println(list1); //[0000,1111]

(4) public int size():获取有效元素的个数

   System.out.println(list.size());

(5) public E remove(int index) :删除 index 位置元素

 List<String> list=new LinkedList();
        list.add("0000");
        list.add("1111");
        list.remove(1);
        System.out.println(list); //[0000]

(6) public boolean remove(E e) :删除指定元素 e

 List<String> list=new LinkedList();
        list.add("0000");
        list.add("1111");
        list.remove("0000");
        System.out.println(list);//[1111]

(7) public boolean contains(E e):是否包含元素 e

 List<String> list=new LinkedList();
     list.add("0000");
     list.add("1111");
     //包含返回true
     System.out.println(list.contains("0000")); 
      //不包含,返回false
    System.out.println(list.contains("9999"));

(8)public E get(int index):获取 index 位置元素

List<String> list=new LinkedList();
      list.add("0000");
      list.add("1111");
   System.out.println(list.get(1)); //1111

(9) public E set(int index, E e):将 index 位置元素设置为 e

List<String> list=new LinkedList();
        list.add("0000");
        list.add("1111");
        list.set(1,"2222");
     System.out.println(list);//[0000, 2222]

(10) public int indexOf(E e):从前往后找,返回第一次 e 出现的下标

List<String> list=new LinkedList();
        list.add("0000");
        list.add("3333");
        list.add(1,"0000");
    System.out.println(list.indexOf("0000"));//0

(11) public int lastIndexOf(E e):从后往前找,返回第一次 e出现的下标

List<String> list=new LinkedList();
        list.add("0000");
        list.add("3333");
        list.add(1,"0000");
     System.out.println(list.lastIndexOf("0000")); // 1

(12) public List<E> subList(int fromIndex, int toIndex):截取 [fromIndex,toIndex) 部分

 List<String> list=new LinkedList();
        list.add("0000");
        list.add("1111");
        list.add("2222");
        list.add("3333");
        list.add("4444");
  System.out.println(list.subList(1,4));//[1111, 2222, 3333]

(13) public boolean isEmpty():判定链表是否为空

 System.out.println(list.isEmpty());

(14) public void clear():清空

 list.clear();
System.out.println(list.size()); //0

LinkedList 的遍历

两种遍历方式:
foreach
迭代器遍历

package day20211018;
import java.util.List;
import java.util.LinkedList;
import java.util.ListIterator;
public class Test {
    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        // foreach 遍历
        for (int e:list) {
            System.out.print(e + " ");
        }
        System.out.println(); // 1 2 3 4
            // 迭代器遍历
            ListIterator<Integer> it = list.listIterator();
            while(it.hasNext()){
                System.out.print(it.next()+ " ");
            }
            System.out.println(); //1 2 3 4
    }
}

补充----链表

链表的概念

链表在物理上:是一种非连续的存储结构;
在逻辑上:数据元素的逻辑顺序是通过链表中的引用来依次链接的;
生活中的实例:类似于火车的结构

链表中的元素存储在一个一个的结点之中;

结点中包含有两个字段:
value:每个结点中元素的值域
next:用来指向下一个结点

需要注意的是:每个结点都是一个对象,而 next只是个引用,并不是对象;

链表的常见结构
  • 单向链表与双向链表

单向链表
在这里插入图片描述
双向链表

在这里插入图片描述

  • 带头链表与不带头链表

不带头结点
在这里插入图片描述
带头结点链表
在这里插入图片描述

  • 循环链表与非循环链表

非循环链表
在这里插入图片描述
循环链表
在这里插入图片描述

:组合起来就有 8 种结构

链表实现
  • (1 ) 模拟实现不带头结点的单链表
package day20211018;

   //模拟实现:不带头结点的单链表
public class SingleLinkList<E> {
   public static class Node<E> {
      E value;
      Node<E> next;

      //构造方法
      public Node(E value) {
         this.value = value;
      }
   }
      Node<E> head; //用来指向链表中的第一个有效结点
      //获取单链表的有效长度
      public int size(){
         Node<E> cur=head;
         int count=0;
         while(null != cur){
            count++;
            cur=cur.next;
         }
         return count;
      }


      // 头插 e
      public void addFirst(E e){
         Node<E> newNode=new  Node<>(e);
         if(null==head){
            head=newNode;
         }else{
            newNode.next=head;
            head=newNode;
         }
      }


      // 尾插e
      public void addLast(E e) {
         Node<E> newNode = new Node<>(e);
         if (null == head) {
            head = newNode;
         } else {
            //找最后一个结点
            //cur 指向第一个结点
            Node<E> cur = head;
            //pre 来标记最后一个结点的位置
            Node<E> pre = null;
            while (null != cur) {
               pre = cur;
               cur = cur.next;
            }
            //插入新结点
            pre.next = newNode;
         }
      }
      //任意位置插入e,第一个数据结点为0号位置
      public boolean addIndex(int position,E e){
         //1.检测参数是否合法
         if(position < 0 || position >= 4){
            throw new IllegalArgumentException("参数不合法");
         }
         if(0==position){
            addFirst(e);
            return true;
         }
         //2.找到position位置的结点,并将其前一个保存(插在position位置的前面)
         Node<E> cur=head;
         Node<E> pre=null;
         while(0 != position){
            pre=cur;
            cur=cur.next;
            position--;
         }
         //3 插入新结点

         Node<E> newNode=new Node<E>(e);
         newNode.next=cur;
         pre.next=newNode;

         return true;
      }

      //删除第一次出现关键字为e的结点
      public void remove(E e){
         Node<E> cur=head;
         Node<E> prev=null;
         //prev 用来标记cur
         while(null != cur){
            if(e.equals(cur.value)){
               cur.value=null;
               if(prev==null){
                  //说明删除的是第一个结点
                 head=cur.next;
            }else{
                  //删除其他结点
                  prev.next=cur.next;
               }
            return;
            }
            prev=cur;
            cur=cur.next;
         }
      }

      //删除所有值为e的结点
     public void removeAllKey(E e) {
        //时间复杂度O(N^2)
        /*while(contains(e)){
           remove(e);
        }*/
        Node<E> cur=head;
        Node<E> prev=null;
        while(null!= cur){
           if(e.equals(cur.value)){
              //删除结点
              cur.value=null;
              if(prev==null){
                 head=cur.next;
                 cur=head;
              }else{
                 prev.next=cur.next;
                 cur=prev.next;
              }

           }else{
              prev=cur;
              cur=cur.next;
           }

        }
      }

      //查找是否包含关键字 e
      public boolean contains(E e) {
         Node<E> cur=head;
         while(null!=cur){
            if(e.equals(cur.value)){
               return true;
            }
            cur=cur.next;
         }
         return false;
      }
     
      @Override
      public String toString(){
         Node<E> cur=head;
         String s="[";
         while(null!= cur){
            s+=cur.value;
            if(null !=cur.next){
               s+=",";
            }

            cur=cur.next;
         }
         s+="]";
         return s;
      }

      public static void main(String[] args) {
         SingleLinkList<Integer> s=new SingleLinkList<>();
         System.out.println(s); //[]
         //测试尾插
         s.addLast(1);
         s.addLast(2);
         s.addLast(3);
         s.addLast(4);
         System.out.println(s); //[1,2,3,4]
         System.out.println(s.size()); //4
         //测试是否包含元素e
         System.out.println(s.contains(2)); //true
         System.out.println(s.contains(5)); //false
         //测试头插
         s.addFirst(0);
         System.out.println(s);  //[0,1,2,3,4]
         //测试任意位置插入
         s.addIndex(0,0);
         System.out.println(s); //[0,0,1,2,3,4]
         s.addIndex(3,5);
         System.out.println(s); //[0,0,1,5,2,3,4]
         //删除所有值为0的元素
         s.removeAllKey(0);
         System.out.println(s); //[1,5,2,3,4]
         //测试remove
         s.remove(5);
         System.out.println(s); //[1,2,3,4]
      }
   }


动起小手往下戳~~
在这里插入图片描述

总结—ArrayList 与 LinkedList 的联系与区别

  • 相同点:两者均实现了 List 接口;
  • 不同点体现在以下方面

(1)由于ArrayList 底层采用数组来存储元素,支持随机访问;
(2)LinkedList 底层采用双向链表结构,不支持随机访问;
(3)ArrayList 支持扩容,LinkedList 没有扩容这个概念;
(4)在存储空间上:ArrayList 在物理上是一定连续的,LinkedList 逻辑上是连续的,但物理上不一定连续;
(5)在任意位置进行元素的插入与删除时,ArrayList 需要通过搬移元素后,将位置腾出后,才可以进行插入,因此,时间复杂度为O(N),效率慢;
LinkedList 只需要修改引用的指向即可,时间复杂度为O(1),效率较高;
换句话说:在元素进行高效访问时,优先考虑 ArrayList,在进行任意位置插入与删除元素时,优先考虑 **LinkedList**.

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值