LinkedList 基本使用

举报
兮动人 发表于 2022/09/25 23:10:27 2022/09/25
【摘要】 LinkedList 基本使用

1. LinkedList 简介

  1. LinkedList 底层实现了 双向链表和双端队列 特点
  2. 可以添加任意元素(元素可以重复),包括null
  3. 线程不安全,没有实现同步

2. LinkedList 底层操作机制

在这里插入图片描述

  1. LinkedList 底层维护了一个双向链表.
  2. LinkedList 中维护了两个属性firstlast分别指向首节点和尾节点
  3. 每个节点(Node对象) ,里面又维护了 prev、 next. item 三个属性,其中 prev 指向前一个,通过 next 指向后一个节点。 最终实现双向链表
  4. 所以 LinkedList 的元素的添加和删除,不是通过数组完成的,相对来说效率较高。
  5. 模拟一个简单的双向链表,如:
    在这里插入图片描述
  • 双向链表的简单使用
public class LinkedList01 {

    public static void main(String[] args) {

        // 模拟一个简单的双向链表

        Node tom = new Node("tom");
        Node jack = new Node("jack");
        Node xdr = new Node("xdr");

        //连接三个点,形成双向链表
        // tom->jack->xdr
        tom.next = jack;
        jack.next = xdr;
        // xdr->jack->tom
        xdr.pre = jack;
        jack.pre = tom;

        Node first = tom;//让 first 引用指向 jack,就是双向链表的头节点
        Node last = xdr; //让 last 引用指向 xdr,就是双向链表的尾节点

        // 从头到尾进行遍历
        System.out.println("===从头到尾进行遍历===");
        while (true) {
            if (first == null) {
                break;
            }
            //输出 first 信息
            System.out.println(first);
            first = first.next;
        }

        //从尾到头的遍历
        System.out.println("====从尾到头进行遍历====");
        while (true) {
            if (last == null) {
                break;
            }
            //输出 last 信息
            System.out.println(last);
            last = last.pre;
        }

    }
}

// 定义一个 Node 类,Node 对象,表示双向链表的一个节点
class Node {
    public Object item; // 真正存放的数据
    public Node next; // 指向后一个节点
    public Node pre; // 指向前一个节点

    public Node(Object name) {
        this.item = name;
    }

    public String toString() {
        return "Node name=" + item;
    }
}

在这里插入图片描述

  • 在链表中插入元素,如:在 jack 和 xdr 中间插入一个对象 mike
	//先创建一个 Node 结点,name 就是 mike
	Node mike = new Node("mike");
	//下面就把 mike 加入到双向链表了
	mike.next = xdr;
	mike.pre = jack;
	xdr.pre = mike;
	jack.next = mike;
	
	//让 first 再次指向 tom
	first = tom;//让 first 引用指向 tom,就是双向链表的头结
	System.out.println("===从头到尾进行遍历===");
	while (true) {
	    if (first == null) {
	        break;
	    }
	    //输出 first 信息
	    System.out.println(first);
	    first = first.next;
	}
	
	// 从尾到头进行遍历
	last = xdr; //让 last 重新指向最后一个节点
	//从尾到头的遍历
	System.out.println("====从尾到头进行遍历====");
	while (true) {
	    if (last == null) {
	        break;
	    }
	    //输出 last 信息
	    System.out.println(last);
	    last = last.pre;
	}

在这里插入图片描述

3. LinkedList 源码分析

1、案例:打断点进行源码分析

	LinkedList linkedList = new LinkedList();
	linkedList.add(1);
	linkedList.add(2);
1. LinkedList linkedList = new LinkedList();
   public LinkedList() {}
   
2. 这时 linkeList 的属性 first = null  last = null

3. 执行 添加
    public boolean add(E e) {
         linkLast(e);
         return true;
     }  
     
4.将新的结点,加入到双向链表的最后
  void linkLast(E e) {
     final Node<E> l = last;
     final Node<E> newNode = new Node<>(l, e, null);
     last = newNode;
     if (l == null)
         first = newNode;
     else
         l.next = newNode;
     size++;
     modCount++;
 }

2、演示删除节点的源码:linkedList.remove(); 这里默认删除的是第一个节点

1. 执行 removeFirst
   public E remove() {
       return removeFirst();
   }
   
2. 执行
   public E removeFirst() {
       final Node<E> f = first;
       if (f == null)
           throw new NoSuchElementException();
       return unlinkFirst(f);
   }
   
3. 执行 unlinkFirst, 将 f 指向的双向链表的第一个结点拿掉
   private E unlinkFirst(Node<E> f) {
       // assert f == first && f != null;
       final E element = f.item;
       final Node<E> next = f.next;
       f.item = null;
       f.next = null; // help GC
       first = next;
       if (next == null)
           last = null;
       else
           next.prev = null;
       size--;
       modCount++;
       return element;
   }

4. LinkedList 增删改查案例

  • 删除一个节点
LinkedList linkedList = new LinkedList();
   linkedList.add(1);
   linkedList.add(2);

   System.out.println(linkedList);
   linkedList.remove();
   System.out.println(linkedList);

在这里插入图片描述

  • 修改某个节点对象,index 索引是按照 0 开始编号的
LinkedList linkedList = new LinkedList();
	linkedList.add(1);
	linkedList.add(2);
	linkedList.add(3);
	
	System.out.println(linkedList);
	linkedList.remove();
	System.out.println(linkedList);
	
	linkedList.set(1, 2233);
	
	System.out.println(linkedList);

在这里插入图片描述

  • 得到某个结点对象,get(1) 是得到双向链表的第二个对象
Object o = linkedList.get(1);
System.out.println(o);

在这里插入图片描述

  • LinkedList 是 实现了List接口,遍历方式可以用 迭代器、增强for、普通for 进行遍历
	System.out.println("===迭代器遍历===");
	Iterator iterator = linkedList.iterator();
	while (iterator.hasNext()) {
	    Object next = iterator.next();
	    System.out.println("next=" + next);
	}
	
	System.out.println("===增强for循环遍历===");
	for (Object o : linkedList) {
	    System.out.println("o=" + o);
	}
	
	System.out.println("===普通for循环遍历===");
	for (int i = 0; i < linkedList.size(); i++) {
	    System.out.println(linkedList.get(i));
	}

在这里插入图片描述

5. ArrayList和LinkedList比较

在这里插入图片描述

  • 如何选择 ArrayList 和 LinkedList :
  1. 如果改查的操作多,选择ArrayList
  2. 如果增删的操作多,选择LinkedList
  3. 一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList
  4. 在一个项目中,根据业务灵活选择,一个模块使用的是ArrayList,另外一个模块是LinkedList,也就是说,要根据业务需求来进行选择。
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。