• LinkedList底层结构与源码分析


    LinkedList全面说明

            1)LinkedList底层实现了双向链表和双端队列特点;

            2)可以添加任何元素(元素可以重复),包括重复null值;

            3)线程不安全,没有实现同步。

    LinkedList的底层操作机制

            1)LinkedList底层维护了一个双向链表;

            2)LinkedList中维护了两个属性first和last分别指向首节点和尾节点;

            3)每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点,最终实现双向链表;

            4)LinkedList的元素的添加和删除(通过改变node节点指针指向来实现增加删除和添加),不是通过数组完成的(数组需要扩容和元素复制),相对来说效率较高。

    1. transient Node first;
    2. transient Node last;
    3. private static class Node {
    4. E item;
    5. Node next;
    6. Node prev;
    7. Node(Node prev, E element, Node next) {
    8. this.item = element;
    9. this.next = next;
    10. this.prev = prev;
    11. }
    12. }

    模拟一个简单的双向链表

    1. public class LinkedList1 {
    2. public static void main(String[] args) {
    3. //模拟一个简单的双向链表
    4. Node jack = new Node("jack");
    5. Node tom = new Node("tom");
    6. Node hsp = new Node("hsp");
    7. LinkedList linkedList = new LinkedList();
    8. //连接2个节点,形成双向链表
    9. //jack->tom->hsp
    10. jack.next = tom; //jack的后一个节点指向tom
    11. tom.next = hsp;//tom的后一个节点指向hsp
    12. //hsp->tom->jack
    13. hsp.prev = tom;//hsp的前一个节点指向tom
    14. tom.prev = jack;//tom的前一个节点指向jack
    15. Node first = jack;//让first引用指向jack,为双向链表的头节点
    16. Node last = hsp;//让last引用指向hsp,为双向链表的尾节点
    17. //从头到尾遍历
    18. System.out.println("---------从头到尾遍历--------");
    19. while (first != null) {
    20. System.out.println(first);
    21. first = first.next;
    22. }
    23. //从尾到头遍历
    24. System.out.println("---------从尾部到头部遍历--------");
    25. while (last != null) {
    26. System.out.println(last);
    27. last = last.prev;
    28. }
    29. //链表添加数据/对象
    30. Node smith = new Node("smith");
    31. smith.next = hsp;
    32. smith.prev = tom;
    33. tom.next = smith;
    34. hsp.prev = tom;
    35. first = jack;//双向链表的头节点
    36. System.out.println("---------从头到尾遍历--------");
    37. while (first != null) {
    38. System.out.println(first);
    39. first = first.next;
    40. }
    41. }
    42. //定义一个Node类,Node对象表示双向链表的一个节点
    43. static class Node {
    44. public Object item; //存放真正的元素
    45. public Node next; //指向后一个节点
    46. public Node prev; //指向前一个节点
    47. public Node(Object item) {
    48. this.item = item;
    49. }
    50. @Override
    51. public String toString() {
    52. return "Node{" +
    53. "item=" + item +
    54. '}';
    55. }
    56. }
    57. }

    LinkedList底层源码分析

     创建一个LinkedList无参构造对象,此时LinkedList的属:first = null  last = null size = 0

    1. LinkedList linkedList = new LinkedList<>();
    2. //内部为一个无参构造方法
    3. //此时LinkedList的属:first = null last = null size = 0
    4. public LinkedList() {
    5. }

    执行add(E e)方法向LinkedList中添加数据

    1. //第1次添加元素
    2. linkedList.add(1);
    3. //第2次添加元素
    4. linkedList.add(1);
    5. //执行add(E e)方法向LinkedList中添加一条数据
    6. public boolean add(E e) {
    7. linkLast(e);
    8. return true;
    9. }
    10. //将新的节点加入双向链表的最后
    11. void linkLast(E e) {
    12. //此时last为null,因此l=null
    13. final Node l = last;
    14. // 创建节点:首次添加元素1, l = null last = null e = 1
    15. // 创建节点:第二次添加元素2 之前l指向1,此时将l赋值给prev,此时prev指向1
    16. final Node newNode = new Node<>(l, e, null);
    17. //将last的指向新的节点->2,此时指向1的last断裂
    18. last = newNode;
    19. if (l == null)
    20. //首次添加元素 first(null)->1<-last(null)
    21. first = newNode;
    22. else
    23. //此时next指向2
    24. //first(null)->1<->2<-last(null)
    25. l.next = newNode;
    26. size++;
    27. modCount++;
    28. }

    执行remove(int index)方法向LinkedList中移除数据

    1. linkedList.add(2);
    2. linkedList.add(3);
    3. linkedList.add(4);
    4. //移除下标为2的数据,移除元素3
    5. linkedList.remove(2);
    6. System.out.println("linkedList=" + linkedList);
    7. }
    8. public E remove(int index) {
    9. //判断下标是否越界
    10. checkElementIndex(index);
    11. return unlink(node(index));
    12. }
    13. E unlink(Node x) {
    14. // assert x != null;
    15. //此时指向关系为 first(null)->1<->2<->3<->4<-last(null)
    16. //获取下标为2的内容为3
    17. final E element = x.item;
    18. //获取下标为2的内容(3)的后一个指向,该指标指向4
    19. final Node next = x.next;
    20. //获取下标为2的内容(3)的前一个指向,该指标指向2
    21. final Node prev = x.prev;
    22. if (prev == null) {
    23. first = next;
    24. } else {
    25. //此时指标指向不为null
    26. //将3的下一个prev指向(4指向3的prev)去指向3的指向
    27. prev.next = next;
    28. //将3指向2的指向置为空,此时3指向2的prev消失 help GC
    29. x.prev = null;
    30. }
    31. //此时指标指向不为null
    32. if (next == null) {
    33. last = prev;
    34. } else {
    35. //将4的前一个指向指向3的前一个指向
    36. next.prev = prev;
    37. //将3的下一个指向置为空
    38. x.next = null;
    39. }
    40. x.item = null;
    41. size--;
    42. modCount++;
    43. return element;
    44. }

    总结:

    LinkedList全面说明

            1)LinkedList底层实现了双向链表和双端队列特点;

            2)可以添加任何元素(元素可以重复),包括重复null值;

            3)线程不安全,没有实现同步。

    LinkedList的底层操作机制

            1)LinkedList底层维护了一个双向链表;

            2)LinkedList中维护了两个属性first和last分别指向首节点和尾节点;

            3)每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点,最终实现双向链表;

            4)LinkedList的元素的添加和删除(通过改变node节点指针指向来实现增加删除和添加),不是通过数组完成的(数组需要扩容和元素复制),相对来说效率较高。

  • 相关阅读:
    [开发|鸿蒙] 鸿蒙OS开发环境搭建(笔记,持续更新)
    自动驾驶(八十四)---------中间件对比分析
    柯西中值定理习题
    神经网络的图像识别技术,语音识别深度神经网络
    mojo安装
    Tomcat日志分割
    【毕业设计】时间序列天气预测系统 - LSTM
    智能算法--基于差分进化算法(DE)的神经网络优化UCI数据集
    SpringBoot配置输出的日志文件
    Spring Boot 配置文件
  • 原文地址:https://blog.csdn.net/hzz_321/article/details/126910452