Java基础学习(十)

news/2025/1/26 18:14:58/文章来源:https://www.cnblogs.com/victoria6013/p/18692033

Java基础学习(十):集合

目录
  • Java基础学习(十):集合
    • 概念
    • 数据结构
    • 泛型
    • Collection
    • List
    • ArrayList
    • LinkedList
    • Set
    • HashSet
    • LinkedHashSet
    • TreeSet

本文为个人学习记录,内容学习自 黑马程序员


概念

  • 数组长度固定,不够灵活,因此出现了集合

  • 集合 vs 数组

    • 长度:数组的长度固定,集合长度可变(会在添加数据时自动扩容,删除数据时自动压缩)
    • 存储类型:数组可以存储所有数据类型,集合只能存储引用数据类型,如果要存储基本数据类型的话需要将其转换成对应包装类
  • 集合可以分成两大类:单列集合Collection 和 双列集合Map

  • 单列集合中的常用集合:

    • List 系列集合:添加的元素是有序、可重复、有索引的
    • Set 系列集合:添加的元素是无序、不重复、无索引的
    • 下图中 Collection,List,Set为接口,其余为实现类,箭头表示继承/实现关系
    图10-1

数据结构

  • 数据结构是计算机底层存储、组织数据的方式

  • 数据结构是为了更加方便地管理和使用数据,需要结合具体的应用场景进行选择,合适的数据结构能带来更高的运行或存储效率

  • 常见数据结构:栈,队列,数组,链表,二叉树,二叉查找树,平衡二叉树,红黑树

  • 栈:后进先出,先进后出

  • 队列:先进先出,后进后出

  • 数组:查询快,增删慢

    • 查询速度快:通过地址值找到数组,再通过索引找到元素,查询任意数据耗时相同,元素在内存中连续存储
    • 删除效率低:要将原始的数据删除,同时后面每个数据前移
    • 添加效率低:添加位置后地每个元素后移,再添加元素
  • 链表:查询慢,增删快

    • 链表中的每一个元素称为结点/节点(node),每个结点都是独立对象,在内存中不连续,结点中存储具体数据和下一个结点的地址

    • 查询速度慢:无论哪个数据都要从头开始查找

    • 删除和添加效率高:只要修改结点指向的地址就可以了

      图10-2
    • 单向链表 vs 双向链表:双向链表中不仅存储了具体值和下一个结点地址,还存储了上一结点地址,能提高查找效率

    • 基本概念:

      • 树中的每个 节点 都是一个独立对象

      • 节点 A 如果下方连接了节点 B 和 C,则称节点 A 为父节点,节点 B 和 C 从左到右排列时称 B 为左子节点,C 为右子节点

      • 节点中存储了当前节点的数据、父节点地址、左子节点地址和右子节点地址,如果不存在则记为 null

      • 将节点的子节点数量称为 ,例如二叉树中任意节点的度<= 2

      • 将树的总层数称为 树高

      • 将树的最顶层节点称为 根节点

      • 将根节点的左子节点及其以下的内容称为 根节点的左子树,同理还有 根节点的右子树,其它节点也有左子树和右子树的概念

      图10-3
  • 二叉树

    • 满足任意节点最多有两个子节点的树为二叉树
    • 普通二叉树的弊端:没有顺序要求,查找效率低下
    • 二叉树遍历方式(适用于所有二叉树):
      • 前序遍历:从根节点开始,按照当前节点-左子节点-右子节点的顺序遍历,例如上面的树遍历顺序为 20-18-16-19-23-22-24
      • 中序遍历:从最左边的子节点开始,按照左子节点-当前节点-右子节点的顺序遍历,例如上面的树遍历顺序为 16-18-19-20-22-23-24,对二叉查找树进行中序遍历可以得到从小到大排列的数据,因此这种方法最为常用
      • 后序遍历:从最左边的子节点开始,按照左子节点-右子节点-当前节点的顺序遍历,例如上面的树遍历顺序为 16-19-18-22-24-23-20
      • 层序遍历:从根节点开始一层层遍历,例如上面的树遍历顺序为 20-18-23-16-19-22-24
  • 二叉查找树:

    • 又称二叉排序树或者二叉搜索树
    • 满足三个条件:任意节点最多有两个子节点,任意节点左子树上的值都小于当前节点,任意节点右子树上的值都大于当前节点
    • 数据存储规则:小的存左边,大的存右边,一样的不存
    • 二叉查找树查找方式:从根节点开始查,如果目标值小于当前节点值,则向左子树查找,如果大于当前节点值,则向右子树查找
    • 二叉查找树的优势:相比于普通二叉树提高了查找效率
    • 二叉查找树的弊端:可能存在左子树和右子树高度相差过大的情况,会大大降低查找效率
  • 平衡二叉树

    • 平衡二叉树就是在二叉查找树的基础上,规定任意节点左右子树高度差不超过1

    • 平衡二叉树的实现机制 —— 旋转机制

      • 旋转:分成左旋(逆时针旋转)和右旋(顺时针旋转)
      • 触发时机:当添加一个节点后,该树不再是一颗平衡二叉树时触发旋转
    • 平衡二叉树旋转流程:

      1. 确定支点:从添加的节点开始,不断往父节点找不平衡的节点作为支点,将支点及其下的内容作为一个整体旋转,其余不变

      2. 确定旋转方向:将支点视为根节点,根据插入的节点位置分成四种情况:

        • 左左:当根节点左子树的左子树有节点插入导致不平衡时,只需要一次右旋
        • 左右:当根节点左子树的右子树有节点插入导致不平衡时,需要先将根节点的左子树单独进行一次左旋,旋转后就相当于”左左“的插入情况了,这时再进行一次右旋即可
        • 右右:当根节点右子树的右子树有节点插入导致不平衡时,只需要一次左旋
        • 右左:当根节点右子树的左子树有节点插入导致不平衡时,需要先将根节点的右子树单独进行一次右旋,旋转后就相当于”右右“的插入情况了,这时再进行一次左旋即可
      3. 进行旋转:如果是左旋,就将原来的右子节点升级到支点所在位置,原来的支点降级为新支点的左子节点;如果是右旋,就将原来的左子节点升级到支点所在位置,原来的支点降级为支点的右子节点

        图10-4

      4. 复杂情况:如果在左旋时,原来的右子节点已经有左子节点了,不会将该左子节点一块升级,而是作为降级后的新左子节点的右子节点;右旋同理

        图10-5

  • 红黑树

    • 红黑树是一种自平衡的二叉查找树,但它并不是平衡二叉树

    • 红黑树的每个节点上都有存储位表示节点的颜色,每一个节点可以是红或者黑

    • 红黑树不是高度平衡的,它的平衡是通过红黑规则实现的

    • 红黑树 vs 平衡二叉树:平衡二叉树是高度平衡的,查找效率很高,但添加数据时由于可能存在多次旋转,添加效率不高;红黑树不一定是高度平衡的,但增删改查效率都很高

    • 红黑树的红黑规则:

      • 每一个节点或者是红色的,或者是黑色的
      • 根节点必须是黑色
      • 如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为 Nil,这些 Nil 视为叶节点,叶节点为黑色的
      • 如果某一个节点是红色的,那么它的子节点必须是黑色的(不能出现两个红色节点相连的情况)
      • 对每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
      图10-6
    • 红黑树添加节点的规则:

      • 默认颜色:添加节点默认是红色的

      • 添加细则如下:

        图10-7

      • 注意:“把父/祖父设置为当前节点再进行判断”:指的是对添加的节点进行处理后,还要再将父/祖父视为添加的节点,再次进行上述判断和处理


泛型

  • JDK5 引入的特性,可以在编译阶段约束操作的数据类型,并进行检查

  • 格式:<数据类型>

  • 泛型的出现:在使用集合时,如果不存在泛型,那么集合中的元素可以是任何引用数据类型,在底层都是使用 Object obj = input;来实现的,而多态是无法使用子类特有的方法的,虽然可以通过强制类型转换转换回子类对象,但每种类型都要强转实在太麻烦了。因此泛型被用于约束数据类型,虽然在输入时仍然是使用 Object obj = input;的伪泛型,但在输出时会自动帮我们强转成约束类型

  • 优势:1. 统一数据类型 2. 把运行时期可能出现的问题提前到了编译时期

  • 注意事项:

    1. 泛型只能支持引用数据类型
    2. 指定泛型的具体类型后,传递数据时可以传入该类型或者其子类类型
    3. 创建集合对象时如果不指定泛型,默认是 Object 类型
    4. 泛型中可以指定多个变量,如 <E, T>
  • 泛型可以在很多地方定义:当泛型写在类后面时,是泛型类;写在方法上面时,是泛型方法;写在接口后面时,是泛型接口

    • 泛型类

      • 使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类

      • 格式:修饰符 class 类名<类型> {}

      • 说明:此处的 E 用于记录数据类型,一般写成 T(Type)、E(Element)、K(Key)、V(Value)等

      • 示例:

        public class MyArrayList<E> {Object[] obj = new Object[10];int size;public boolean add(E e) {obj[size] = e;return true;}
        }
        
    • 泛型方法

      • 使用场景:当一个方法中,某个变量的数据类型不确定时,可以定义带有泛型的方法

      • 格式:修饰符 <类型> 返回值类型 方法名(形参) {}

      • 示例:

        public class MyArrayList {public static <E> void add(E e) {// 方法体}
        }
        
    • 泛型接口

      • 使用场景:当一个接口中,某个变量的数据类型不确定时,可以定义带有泛型的接口

      • 格式:修饰符 interface 接口名<类型> {}

      • 两种使用方式:

        1. 实现类给出具体类型

          public class MyArrayList implements List<String> {// 重写方法,方法中不存在泛型
          }
          
        2. 实现类延续泛型,创建实现类对象时再确定类型

          public class MyArrayList<E> implements List<E> {// 重写方法,方法中存在泛型
          }
          
  • 泛型的通配符

    • ? 表示不确定的类型

    • 在 ? 的基础上可以进一步限定类型

      • ?:表示可以传递任何类型

        注意:使用 ? 表示能传递任何类型时,不需要在修饰符和返回值类型之间写泛型

        public static void method(ArrayList<?> list) {// 方法体
        }
        
      • ? extends E:表示可以传递 E 或者 E 所有的子类类型

        public static void method(ArrayList<? extends GrandFather> list) {// 方法体
        }
        
      • ? super E:表示可以传递 E 或者 E 所有的父类类型

        public static void method(ArrayList<? super Son> list) {// 方法体
        }
        
  • 应用场景:如果在定义类、方法、接口时存在不确定的类型,就可以定义泛型类、泛型方法、泛型接口;如果类型不确定,但能传递的参数在某个继承结构中,就可以使用泛型的通配符


Collection

  • Collection 是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的

  • 常用方法:

    方法名 说明
    public boolean add(E e) 把给定的对象添加到当前集合中
    public void clear() 清空集合中所有的元素
    public boolean remove(E e) 把给定的对象从当前集合中删除
    public boolean contains(Object obj) 判断当前集合中是否包含给定的对象
    public boolean isEmpty() 判断当前集合是否为空
    public int size() 返回集合中元素的个数
  • 注意事项:

    1. add() 方法的返回值表征添加成功还是失败,如果是 List 系列的集合返回值一定是 true,如果是 set 系列的集合需要看要添加的元素是否已经存在,若已经存在则会添加失败,返回值为 false
    2. remove() 方法的返回值表征删除成功还是失败,删除成功返回 true,若要删除的元素不存在则会删除失败返回 false
    3. contains() 方法底层是调用 equals() 方法来判断是否存在的,所以当集合中存储自定义对象时,需要重写自定义对象的 equals() 方法,否则判断是否存在时不会根据属性值判断,而是根据地址值判断
  • 遍历方式:迭代器遍历,增强型 for 循环遍历,Lambda 表达式遍历

    • 需要注意,由于 Set 系列集合是没有索引的,因此 Collection 集合无法使用普通 for 循环进行遍历

    • 迭代器遍历

      • 路径:java.util.Iterator

      • 迭代器是集合专用的遍历方式

      • Collection 集合获取迭代器对象

        方法名 说明
        Iterator<E> iterator() 返回迭代器对象,默认指向当前集合的 0 索引
      • Iterator 常用方法:

        方法名 说明
        boolean hasNext() 判断当前位置是否有元素,有元素返回 true,否则返回 false
        E next() 获取当前位置元素,并将迭代器对象移向下一个位置
        default void remove() 从集合中删除迭代器对象返回的最后一个元素(当前指向元素的前一个元素)
      • 注意事项:

        1. 若迭代器当前指向的位置没有元素,调用 next() 方法会报错:NoSuchElementException
        2. 迭代器遍历完指针不会复位
        3. 迭代器遍历时,不能用集合的方法进行增加或删除元素,但可以用迭代器自身的方法删除元素
      • 示例:

        ArrayList<String> list = new ArrayList<>();
        Iterator<String> it = list.iterator();
        while (it.hasNext()) {String str = it.next();
        }
        
    • 增强型 for 循环遍历

      • 增强型 for 循环的底层就是通过迭代器实现的,是为了简化迭代器的代码书写才出现的

      • 只有单列集合和数组能够使用增强型 for 循环遍历

      • 示例:

        ArrayList<String> list = new ArrayList<>();
        // 注意事项:str是一个第三方变量,就算修改它的值也不会对数组/集合的元素发生影响
        for (String str: list) {System.out.println(str);
        }
        
    • Lambda 表达式遍历

      • 得益于 JDK8 提出的 Lambda 表达式,提供了一种更简单的遍历集合方式

      • 使用方法:

        方法名 说明
        default void forEach(Consumer<? super T> action): 结合 Lambda 遍历集合
      • 不采用 Lambda 表达式时:

        ArrayList<String> list = new ArrayList<>();
        list.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {						// s依次表示集合中的每一个元素,同样也是第三方变量System.out.println(s);}
        });
        
      • 采用 Lambda 表达式的完整形式时(可以根据具体情况继续简化):

        ArrayList<String> list = new ArrayList<>();
        list.forEach((String s) -> {System.out.println(s);}
        );
        
    • 总结:通常使用增强 for 循环或者 Lambda 表达式实现遍历,如果需要在遍历时删除元素才使用迭代器遍历


List

  • 特点:有序 —— 存和取的元素顺序一致,有索引 —— 可以通过索引操作元素,可重复 —— 存储的元素可以重复

  • List 集合在继承了 Collection 的基础上,多了很多索引操作的方法

  • List 中特有的常见方法:

    方法名 说明
    void add(int index, E element) 在此集合中的指定位置插入指定的元素
    E remove(int index) 删除指定索引处的元素,返回被删除的元素
    E set(int index, E element) 修改指定索引处的元素,返回被修改的元素
    E get(int index) 返回指定索引处的元素
  • 注意事项:

    List 集合有两个 remove() 方法,一个的形参是 int 类型的索引,另一个是元素的类型,前者是根据索引删除元素,后者是根据元素值删除元素。当元素类型是 Integer 时,实参为 int 类型的数据时两种方法都可以调用,此时优先调用“实参类型和形参类型完全一致的方法”,也就是说优先根据索引删除元素

  • List 集合的遍历方式:迭代器遍历,列表迭代器遍历,增强型 for 循环遍历,Lambda 表达式遍历,普通 for 循环遍历

    • 迭代器遍历,增强型 for 循环遍历,Lambda 表达式遍历和 Collection 中的遍历一致

    • 普通 for 循环遍历

      ArrayList<String> list = new ArrayList<>();
      for (int i = 0; i < list.size(); i++) {String s = list.get(i);
      }
      
    • 列表迭代器遍历

      • 路径:java.util.ListIterator

      • List 集合获取迭代器对象

        方法名 说明
        ListIterator<E> listIterator() 返回列表迭代器对象,默认指向当前集合的 0 索引
      • ListIterator 常用方法:

        方法名 说明
        boolean hasNext() 判断当前位置是否有元素,有元素返回 true,否则返回 false
        E next() 获取当前位置元素,并将迭代器对象移向下一个位置
        void add(E e) 将指定元素插入到集合中,插入位置为当前指向的位置,其余元素后置
        void remove() 从集合中删除迭代器对象返回的最后一个元素
    • 总结:在遍历时需要删除元素时使用迭代器,在遍历时需要添加元素时使用列表迭代器,仅仅想遍历时使用增强 for 循环或者Lambda 表达式,如果遍历时需要操作索引则使用普通 for 循环


ArrayList

  • 路径:java.util.ArrayList

  • 底层数据结构是 数组

  • 定义格式:集合类型<数据类型> 集合名 = new 集合类型<数据类型>();

    // <E>:泛型,用于限定集合中的数据类型,E表示具体的数据类型;泛型可以省略,省略后该集合能添加任意类型的数据
    // 在JDK7之后,后面的String可以省略,但是尖括号不能省略
    // 调用无参构造时,默认生成一个初始容量为 10 的空列表
    ArrayList<String> list = new ArrayList<String>();
    
  • 常用方法:

    方法名 说明
    boolean add(E e) 添加元素,返回值表示是否添加成功
    boolean remove(E e) 删除指定元素,返回值表示是否删除成功
    E remove(int index) 删除指定索引的元素,返回被删除元素
    E set(int index, E e) 修改指定索引下的元素,返回原来的元素
    E get(int index) 获取指定索引的元素
    int size() 返回集合长度,也就是集合中元素的个数
    ArrayList<String> list = new ArrayList<>();
    list.add("A");										// 由于add方法返回值一定为true,因此不需要用到该返回值
    list.add("B");
    list.add("C");
    list.add("A");
    System.out.println(list);							// 输出为 [A, B, C, A]
    boolean result = list.remove("A");					// 当需要删除的元素存在时返回true,否则返回false
    System.out.println(list);							// 输出为 [B, C, A],表明存在多个要删除的元素时,只删除第一个
    String str = list.set(1, "D");
    System.out.println(list);							// 输出为 [B, D, A]
    
  • 示例:使用集合存储基本数据类型 —— 包装类的应用

    ArrayList<Integer> list = new ArrayList<>();
    list.add(1);										// 在JDK5之后int和Integer可以互相转化
    
  • 扩展 —— 底层原理:

    • 利用空参创建的集合,在底层创建一个默认长度为 0 的数组
    • 添加第一个元素时,底层会创建一个新的长度为 10 的数组
    • 存满时,扩容为原来的 1.5 倍
    • 如果一次添加多个元素,扩容 1.5 倍后还是放不下,则具体扩容大小以添加元素为准

LinkedList

  • 路径:java.util.LinkedList

  • 底层数据结构是 双向链表

  • 由于双向链表操作首尾元素时速度很快,因此 LinkedList 中提供了很多直接操作首尾元素的特有 API

  • 常用特有方法:

    特有方法 说明
    public void addFirst(E e) 在该列表开头插入指定的元素
    public void addLast(E e) 将指定的元素追加到此列表的末尾
    public E getFirst() 返回此列表中的第一个元素
    public E getLast() 返回此列表中的最后一个元素
    public E removeFirst() 从此列表中删除并返回第一个元素
    public E removeLast() 从此列表中删除并返回最后一个元素

Set

  • 特点:无序 —— 存取顺序不一致,无索引 —— 没有带索引的方法,不重复 —— 可以用来去重复
  • Set 是一个接口,其中的方法基本上与 Collection 中的 API 一致

HashSet

  • 路径:java.util.HashSet
  • 特点:无序,不重复,无索引
  • 底层数据结构是 哈希表
  • 哈希表是一种对于增删改查数据性能都较好的结构,在 JDK8 之前哈希表由数组+链表组成,从 JDK8 开始由数组+链表+红黑树组成
  • 哈希值:对象的整数表现形式
    • 哈希值是根据 hashCode() 方法计算出来的 int 类型的整数
    • 该方法定义在 Object 类中,所有对象都可以调用,默认使用地址值进行计算,因此不同对象的哈希值是不同的
    • 一般情况下,会重写 hashCode() 方法,利用对象内部的属性值计算哈希值,因此只要属性值相同哈希值就相同
    • 在小部分情况下,不同属性或者不同地址计算出来的哈希值也有可能一样(哈希碰撞)
  • HashSet 的底层原理
    • 创建集合对象并添加元素:
      1. 创建一个默认长度为 16 ,默认加载因子为 0.75 的数组(加载因子用于数组扩容)
      2. 根据元素的哈希值跟数组的长度计算出应存入的位置:int index = (数组长度 - 1) & 哈希值
      3. 判断当前位置是否为 null,如果是 null 则直接存入,否则调用 equals() 方法比较对象内部的属性值,如果属性值一样就直接舍弃,如果不一样会存入数组形成链表
      4. 形成链表的具体方式根据 JDK 版本有所不同,在 JDK8 之前是将新元素存入数组,然后将老元素挂在新元素下面;从 JDK8 开始变成了新元素直接挂在老元素下面
      5. 从 JDK8 开始,当链表长度超过8,且数组长度大于等于64时,链表会自动转换成红黑树
    • 注意事项:如果集合中存储的是自定义对象,那么必须重写 hashCode() 和 equals() 方法

LinkedHashSet

  • 路径:java.util.LinkedHashSet
  • 特点:有序,不重复,无索引
  • 底层数据结构是 哈希表,只是每个元素又额外多了一个双向链表的机制记录存储的顺序
  • LinkedHashSet 的有序:HashSet 在遍历时是根据数组索引对数组中的元素和链表进行挨个输出的,由于哈希值的存在这种遍历是无序的;而 LinkedHashSet 引入了双向链表记录了存储顺序(每个元素都记录了前一个、后一个元素的地址值),因此能够有序输出

TreeSet

  • 路径:java.util.TreeSet

  • 特点:可排序,不重复,无索引

  • 底层数据结构是 红黑树

  • TreeSet 可排序:按照元素的默认规则排序

    • 对于数值类型:默认按照从小到大的顺序进行排序
    • 对子字符、字符串类型:按照字符在 ASCII 码表中的数字升序进行排序,字符串对字符逐个比较,例如:"aaa" < "ab" < "aba"
    • 对于自定义类:必须指定比较规则,否则在添加元素时会报错
  • 自定义类指定比较规则:

    • 使用原则:默认使用第一种,只有当第一种方法不能满足比较规则时才使用第二种。比如需要使用自定义规则对字符串进行排序时,由于在 java 中已经对字符串进行了第一种方法的实现(默认按升序排列),此时就需要使用第二种方法

    • 两种方法的区别:第一种方法采用的是 TreeSet 类的空参构造,第二种方法采用的是有参构造且传入比较器

    • 方法一:默认排序/自然排序:Javabean 类实现 Comparable 接口指定比较规则

      // 实现Comparable接口,指定泛型为自身
      public class Student implements Comparable<Student> {private int age;// 构造方法public Student() {}public Student(int age) {this.age = age;}// get/set方法public int getAge() {return age;}public void setAge(int age) {this.age = age;}// 重写抽象方法@Overridepublic int compareTo(Student o) {// this表示当前要添加的元素,o表示已经在红黑树中的元素,比较时从根节点开始比// 返回值为负表明当前要添加的元素是小的,存在左边;返回值为正表明当前要添加的元素是大的,存在右边;返回值为0舍弃// 此处按照年龄升序排列int result = this.getAge() - o.getAge();return result;}
      }
      
    • 方法二:比较器排序:创建 TreeSet 对象时,传递比较器 Comparator 指定规则

      示例:按照字符串长度进行升序排列

      // 由于Comparator是接口,使用匿名内部类的方式传递参数(也可以使用Lambda表达式简化)
      TreeSet<String> set = new TreeSet<>(new Comparator<String>() {// o1表示当前要添加的元素,o2表示已经在红黑树中的元素,比较时从根节点开始比// 返回值为负表明当前要添加的元素是小的,存在左边;返回值为正表明当前要添加的元素是大的,存在右边;返回值为0舍弃// 此处按照字符串长度升序排列@Overridepublic int compare(String o1, String o2) {int result = o1.length() - o2.length();return result;}
      });
      
  • 总结:不同集合的使用场景:

    • ArrayList:集合的元素可以重复时
    • LinkedList:集合中元素可以重复,且增删操作明显多于查询
    • HashSet:如果想对集合中的元素去重
    • LinkedHashSet:如果想对集合中的元素去重,且保证存取顺序
    • TreeSet:如果想对集合中的元素去重并进行排序

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/876044.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java基础学习(十一)

Java基础学习(十一):常见算法 目录Java基础学习(十一):常见算法查找算法排序算法 本文为个人学习记录,内容学习自 黑马程序员查找算法七大查找算法:基本查找(顺序查找)、二分查找(折半查找)、插值查找、斐波那契查找、分块查找、数表查找、哈希查找基本查找核心:从…

[2025.1.26 MySQL学习] 存储引擎

存储引擎 MySQL体系结构图

范围修改查询问题

范围修改查询问题 http://www.nfls.com.cn:10611/up/paper/国家集训队2024论文集.pdf P63 引入 这部分作者定义了半群和幺半群来描述一般的线段树可以做到的结构半群:结合律幺半群:结合律、有幺元交换半群:结合律、交换律形式化问题:(以下是通俗易懂的版本)给定交换半群 …

实现超图S3M数据在Ceisum中的解析、加载

使用超图提供的S3M加载模块。参考文档:S3M_JS使用方法 1. 将项目的Cesium库的Build目录及其内容放在S3M_JS目录中,与S3M_module同级。2. 调用该模块解析、加载S3M数据 const layer = new S3MTilesLayer({context: window.viewer.scene._context,url }) window.viewer.scene.p…

Beyond Compare(文件比较工具) v5.0.5.30614 多语便携版

Beyond Compare是一款功能强大的文件和文件夹比较工具,它能够快速准确地比较文件之间的差异,并提供了一系列强大的功能和工具来帮助用户进行文件和文件夹的同步、合并和备份。 软件功能 - 文件和文件夹比较:Beyond Compare能够快速准确地比较两个文件或文件夹之间的差异,包…

使用EarTrumpet代替windows默认的音量调节功能

前言 https://github.com/File-New-Project/EarTrumpet Windows 默认的音量调节功能挺弱的,要分别调节各个应用的音量得进入二级菜单,麻烦得很 有了这个功能就很方便了 截图安装 老规矩,Github、Microsoft Store、choco、scoop都行 我选的是 scoop 扩展:替换系统的音量控制…

JS-43 document对象_方法/创建元素

document创建元素:createElement(创建元素)createTextNode(创建元素文本)createAttribute(创建元素的属性) 1、document.createElement()document.createElement方法用来生成元素节点,并返回该节点var newDiv=document.createElement(div); 2、document.createTextNode()…

Keydd : 流量包匹配敏感信息的工具

免责声明 工具仅供安全研究与学习之用,若将工具做其他用途,由使用者承担全部法律及连带责任,作者及发布者不承担任何法律及连带责任。信息及工具收集于互联网,真实性及安全性自测!!!​ 项目介绍 一直在使用一些工具插件,来检测流量中的ak、sk、sfz、敏感信息,但是网上…

使用twinkle-tray快捷调整多个显示器的亮度

前言 自从安装了这个小工具,我再也没用过笔记本键盘上的快捷键了~ 介绍Twinkle Tray enables brightness control on external displays in Windows 10 & 11. Even though Windows is capable of adjusting the backlight on most monitors, it doesnt support external m…

ACM寒假集训第二次作业

二分查找 思路 运用二分查找,逐渐逼近所要查找的数字 代码 #include<iostream> using namespace std; int binary_search(int arr[],int l,int r,int x){int mid;while(l<r){mid=(l+r)>>1;if(arr[mid]>=x) r=mid;else l=mid+1;}return arr[l]; }; int main(…

【Java安全】保护Java应用程序:如何嗅探JVM的变量

在这篇文章中,我们回顾如何嗅探JVM的变量可能的方法。这篇文章的主要目的是解释如何保护你的应用程序。计划是进行下一步的攻击。从Dump中读取敏感数据。通过在外部依赖中注入恶意软件来窃取源代码。从Java Dump中窃取数据, 如果有人获得了对Java进程的访问权,他可能会读取敏…

第二讲 二分法

第一题 二分查找 输入一个整数 n 和 n 个整数,保证这 n个整数已经按照从小到大进行排序。 然后输入一个整数 q( q≤100000)代表 q次查询。接下来 q 行,每行含有一个整数 m ,代表一次查询。对于每次查询,使用二分查找判断 m 是否在之前输入的 n个整数中出现过。如果出现,…