2023-05-30 题目

2023-11-12

一、LinkedList

1、特点

线程不安全,底层是链表,删除、插入数据快,查询速度较慢,如果想让其变成线程安全的,可以使用Collections.synchronizedList()方法;

链表底层结构

在这里插入图片描述

2、源码如下
    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;

    private static class Node<E> {
        //节点值
        E item;
        //下一个节点
        Node<E> next;
        //上一个节点
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
2.1、构造方法分析:
    public LinkedList() {
        
    }
// 有参数的构造方法 ,调用新增方法,
    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }

新增方法:

    public boolean add(E e) {
        linkLast(e);
        return true;
    }

//插入尾部
    void linkLast(E e) {
        //把链表的最后一个赋值给 l
        final Node<E> l = last;
        //新增一个node结构如下,前面一个是l,中间是元素,最后一个参数是null
        final Node<E> newNode = new Node<>(l, e, null);
        //last指向最后一个
        last = newNode;
        if (l == null)
            //链表最后一个node是空的话,就一个元素,第一个是新增的
            first = newNode;
        else
            //之前的链表的最后元素中的下一个链接就是newNode
            l.next = newNode;
        //元素个数
        size++;
        //修改结构次数
        modCount++;
    }


    public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }
// 判断元素个数
    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }
  public boolean addAll(int index, Collection<? extends E> c) {
      // 判断元素脚本是否越界
        checkPositionIndex(index);
	// 转数组
        Object[] a = c.toArray();
      //数组长度,0返回
        int numNew = a.length;
        if (numNew == 0)
            return false;
		//当前位置的前缀节点和后缀节点
        Node<E> pred, succ;
        if (index == size) {
            // 如果插入位置为尾部,前驱节点为last,后继节点为null
            succ = null;
            pred = last;
        } else {
            //否则,调用node()方法得到后继节点,再得到前驱节点
            succ = node(index);
            pred = succ.prev;
        }

        for (Object o : a) {
            //循环,new一个node
            @SuppressWarnings("unchecked") E e = (E) o;
            Node<E> newNode = new Node<>(pred, e, null);
            // 链表里面没有元素,这是第一个,头部
            if (pred == null)
                first = newNode;
            else
                //最后一元素的下一个进行赋值
                pred.next = newNode;
            pred = newNode;
        }
		//如果插入位置在尾部,重置last节点
        if (succ == null) {
            last = pred;
        } else {
        //否则,将插入的链表与先前链表连接起来
            pred.next = succ;
            succ.prev = pred;
        }
      //元素个数
        size += numNew;
      //修改次数
        modCount++;
        return true;
    }
	//插入头部第一个
    public void addFirst(E e) {
        linkFirst(e);
    }
	// 
    private void linkFirst(E e) {
        //拿到头部第一个节点
        final Node<E> f = first;
        //新建节点
        final Node<E> newNode = new Node<>(null, e, f);
        first = newNode;
        //如果链表是空的,那么最后一个元素也指向他
        if (f == null)
            last = newNode;
        else
            //之前头部元素变成第二个节点了,前置节点就是新的节点
            f.prev = newNode;
       //元素个数
        size++;
        //修改次数
        modCount++;
    }
2.2、获取数据方法:
    public E get(int index) {
    //查看角标是否越界
        checkElementIndex(index);
        return node(index).item;
    }
    
        Node<E> node(int index) {
        //判断要取的元素在链表中靠近头部还是尾部近
        if (index < (size >> 1)) {
        //靠近头部,正序取
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
        //靠近尾部,倒序取
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }
    
    public E getFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return f.item;
    }

    public E getLast() {
        final Node<E> l = last;
        if (l == null)
            throw new NoSuchElementException();
        return l.item;
    }

2.3、根据对象获取元素位置

从头遍历开始查找

    public int indexOf(Object o) {
        int index = 0;
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null)
                    return index;
                index++;
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item))
                    return index;
                index++;
            }
        }
        return -1;
    }

从尾部开始遍历寻找

    public int lastIndexOf(Object o) {
        int index = size;
        if (o == null) {
            for (Node<E> x = last; x != null; x = x.prev) {
                index--;
                if (x.item == null)
                    return index;
            }
        } else {
            for (Node<E> x = last; x != null; x = x.prev) {
                index--;
                if (o.equals(x.item))
                    return index;
            }
        }
        return -1;
    }
2.4、检查链表中是否包含某个元素
    public boolean contains(Object o) {
        return indexOf(o) != -1;
    }
2.5、删除方法
    public boolean remove(Object o) {
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }


  E unlink(Node<E> x) {
        final E element = x.item;
        final Node<E> next = x.next;//得到后继节点
        final Node<E> prev = x.prev;//得到前驱节点
        //删除前驱指针
        if (prev == null) {
        first = next;//如果删除的节点是头节点,令头节点指向该节点的后继节点
        } else {
        prev.next = next;//将前驱节点的后继节点指向后继节点
        x.prev = null;
        }
        //删除后继指针
        if (next == null) {
        last = prev;//如果删除的节点是尾节点,令尾节点指向该节点的前驱节点
        } else {
        next.prev = prev;
        x.next = null;
        }
        x.item = null;
        size--;
        modCount++;
        return element;
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

2023-05-30 题目 的相关文章

随机推荐

  • LVS常用模式(DR、NAT、TUN)以及ldirector和keepalived

    1 LVS简单介绍 1 lvs定义LVS是Linux Virtual Server的简写 意即Linux虚拟服务器 是一个虚拟的服务器集群系统 LVS集群采用IP负载均衡技术和基于内容请求分发技术 调度器具有很好的吞吐率 将请求均衡地转移到
  • Java学习教程,Java从入门到精通,全套Java视频教程+笔记+配套工具

    目录 一 大纲 一 Java基础 二 计算机基础 三 工具的使用 四 数据库 五 web前端 六 JavaWeb 七 框架 八 互联网分布式技术 发现身边很多自学java却放弃的 真的挺可惜的 白白浪费了几个月宝贵的时间 且放弃一次 就会有
  • 第二十二章 Spring AOP⾥⾯的代理知识

    1 静态代理和动态代理 什么是代理 为某 个对象创建 个代理对象 程序不直接 原本的对象 是由创建的代理对象来控制对原对象 通过代理类这中间 层 能有效控制对委托类对象的直接访问 也可以很好地隐藏和保护委托类对象 同时也为实施不同控制策略预
  • 05-网络的四层协议和七层协议

    TCP IP网络分层模型 TCP IP的设计创造性的提出了分层的概念 把复杂的网络通信划分出多个层次 再为每一个层次分配不同的职责 层次内只专心做好自己的事情 用分而治之的思想把一个大麻烦拆分成了数个小麻烦 从而解决了网络的难题 TCP I
  • JAVA中的for循环使用方法

    一 循环结构 1 概念 在学习Java里的循环之前 我们先来了解一下到底什么是循环 以及循环的作用 我们先来看下面这张图 大家想一下 我们在400米的跑道上参加万米长跑 正常情况下要跑25圈 这25圈每一圈的跑步过程其实都是一样的 相当于是
  • springboot过滤器和拦截器

    一 过滤器和拦截器的区别 1 过滤器和拦截器触发时机不一样 过滤器是在请求进入容器后 但请求进入servlet之前进行预处理的 请求结束返回也是 是在servlet处理完后 返回给前端之前 2 拦截器可以获取IOC容器中的各个bean 而过
  • Volatility3内存取证工具使用详解

    Volatility 介绍 Volatility是一款开源的内存取证分析工具 是一款开源内存取证框架 能够对导出的内存镜像进行分析 通过获取内核数据结构 使用插件获取内存的详细情况以及系统的运行状态 支持Windows Linux MaC
  • org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder 找不到依赖包

    org springframework boot autoconfigure jdbc DataSourceBuilder 找不到依赖包 org springframework boot autoconfigure jdbc DataSou
  • PowerOJ2546: fork【C++ STL __gnu_cxx::rope】

    题目链接 我们可以这样定义一个可持久化数组 rope
  • MIPI TX控制器的设计

    MIPI接口在移动设备中被广泛应用 主要用于传输图像传感器 液晶显示器等外设的数据 以MIPI DPHY v1 2为例 它包含一个CLK lane和若干个DATA lane 可配置 每个lane的最高速率可达到2 5Gbps 对比SerDe
  • 向win7旗舰版U盘启动盘 添加usb3.0driver

    以前的主板usb采用的是ehci controller 仅支持usb2 0 而现在的主板一般采用xhci controller 同时支持usb2 0和usb3 0 win7的镜像安装包里面的驱动并没有xhci的驱动 所以在如今的很多新平台的
  • 怎么样对阿里云ECS主机进行绑定域名

    首先我有个阿里的 域名 虚拟云主机 搭建了一个wordpress 的网站 地址为 www liuxun name wordpress liuxun name wordpress 现在我想把一个阿里云的ECS主机 里面装了tomcat 希望以
  • GET请求里的body问题

    故事还得从一个bug说起 今天有人问我 为什么发到后端的请求400了 我说肯定是参数不对 你去检查检查GET POST之类的方法写没写对 要么就是字段没对上 无非是这几个问题 然后他说检查过了 没问题啊 我不太相信 但是看了看前端发送的请求
  • springmvc 03(JSR303和拦截器)

    目录 一 JSR303 1 服务端验证 2 步骤 二 拦截器 1 简介 2 拦截器与过滤器 2 1 什么是过滤器 2 2 拦截器和过滤器的区别 3 拦截器案例 3 1 使用原理 一 JSR303 1 服务端验证 2 步骤 1 导入pom x
  • 【数据结构】6.5 红黑树(C++)

    数据结构 6 5 红黑树 没有学过二叉搜索树 也叫二叉排序树或二叉查找树 的小伙伴们建议先学习一下 这样阅读会更轻松哦 点我学习二叉搜索树 目录 一 红黑树的概念和性质 二 红黑树的存储结构和声明 三 红黑树的构建过程 四 红黑树的实现 1
  • Windows7上使用VS2013编译Caffe源码(不带GPU支持)步骤

    1 从https github com BVLC caffe 通过git clone下载caffe源码 master分支 版本号为09868ac git clone https github com BVLC caffe git 2 先使用
  • Visio画出简单的拓扑图

    1 选择类别 类别 网络 基本网络图 2 画图 在左边选择 模具 上方选择 连接线
  • Ubuntu下编译并运行C++代码

    安装完Ubuntu后 用户目录有时候也叫 home 文件夹或者主文件夹 它的路径是 home username 其中 username 就是我们登录 Linux 时使用的用户名 Linux 会在 home 目录下为每一个登录的用户创建一个文
  • Java中泛型

    Thinking in Java 第15章笔记 即使使用了接口 就要求代码必须使用特定的接口 对程序的约束也还是太强了 我们希望达到的目的是编写更通用的代码 要使代码能够应用与 某种不具体的类型 而不是一个具体的接口或类 泛型这个术语的意思
  • 2023-05-30 题目

    一 LinkedList 1 特点 线程不安全 底层是链表 删除 插入数据快 查询速度较慢 如果想让其变成线程安全的 可以使用Collections synchronizedList 方法 链表底层结构 2 源码如下 Pointer to