当前位置: 首页 > news >正文

十三、集合进阶——单列集合 及 数据结构

单列集合 及 数据结构

  • 13.1 集合体系结构
    • 13.1.2 单列集合
      • 1. Collection
      • 2.Collection 的遍历方式
        • 迭代器遍历
        • 增强for遍历
        • Lambda表达式遍历
      • 3.List集合
        • List集合的特有方法
        • List集合的遍历方式
        • 五种遍历方式对比
      • 4.数据结构
        • 1).栈
        • 2).队列
        • 3)数组
        • 4)链表
        • 小结
        • 5)树
        • 6)二叉查找树
        • 7)平衡二叉树
          • 平衡二叉树旋转机制——左旋
          • 平衡二叉树旋转机制——右旋
          • 平衡二叉树需要旋转的四种情况
        • 8)红黑树
          • 添加节点的规则
      • 5.ArrayList集合
        • 1.ArrayList集合底层原理
        • 2.LinkedList集合
        • 3.迭代器底层源码解析
      • 6.泛型深入
        • 1)泛型概述
        • 2)泛型类
        • 3)泛型方法
        • 4)泛型接口
        • 5)泛型的继承和通配符
        • 总结
      • 7.Set系列集合
        • 1)HashSet
        • 2)LinkedHashSet
        • 3)TreeSet
      • 8.单列集合使用场景


13.1 集合体系结构

在这里插入图片描述
在这里插入图片描述

13.1.2 单列集合

在这里插入图片描述

在这里插入图片描述

  • List系列集合:添加的元素是有序、可重复、有索引。
  • Set系列集合:添加的元素是无序、不重复、无索引。

1. Collection

Collection 是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的。
在这里插入图片描述

public static void main(String[] args) {/*注意点:* Collection 是一个接口,我们不能直接创建他的对象。* 所以,在学习它的方法时,只能创建他实现类的对象* 实现类:ArrayList** 目的:为了学习Collection接口里面的方法。*/Collection<String> coll = new ArrayList<>();//0.添加元素System.out.println("-------------0.添加元素-------------");/*细节1:如果要往List系列集合中添加数据,那么方法永远返回true,因为List系列的是允许元素重复的。* 细节2:如果要往Set系列集合中添加数据,如果当前要添加元素不存在,方法返回true,表示添加成功。* 如果当前要添加的元素已经存在,方法返回false,表示添加失败* 因为Set系列的集合不允许重复。*/coll.add("zhangsan");coll.add("aaa");coll.add("bbb");coll.add("ccc");System.out.println(coll); // [zhangsan, aaa, bbb, ccc]//1.清空System.out.println("-------------1.清空-------------");
//        coll.clear();System.out.println(coll); // []//2.删除//细节1:因为Collection里面定义的是共性的方法,所以此时不能通过索引删除,只能通过元素的对象进行删除。//细节2:方法会有一个返回值,删除成功返回true,删除失败返回false。System.out.println("-------------2.删除-------------");coll.remove("aaa");System.out.println(coll); // [zhangsan, bbb, ccc]//3.判断元素是否包含/*细节:底层是依赖equals方法进行判断是否存在的。* 所以,如果集合中存储的是自定义对象,也想通过contains方法来判断是否包含,那么在javabean类中,一定要重写equals方法*/System.out.println("-------------3.判断元素是否包含-------------");System.out.println(coll.contains("aaa")); //falseSystem.out.println(coll.contains("bbb")); // trueSystem.out.println("------------------------------------------");//4.判断是否为空System.out.println("-------------3.判断元素是否包含-------------");System.out.println(coll.isEmpty()); //falseSystem.out.println("------------------------------------------");//5.获取集合的长度int size = coll.size();System.out.println(size); // 3}

Contains方法 细节

public static void main(String[] args) {//0.创建集合对象Collection<Student> coll = new ArrayList<>();//1.创建三个学生对象Student s1 = new Student("zhangsan", 23);Student s2 = new Student("lisi", 25);Student s3 = new Student("wangwu", 26);//2.把学生对象添加到集合中coll.add(s1);coll.add(s2);coll.add(s3);//3.判断集合中某一个学生对象是否包含Student s4 = new Student("zhangsan", 23);/*因为contains方法在底层依赖equals方法判断对象是否一致的。如果存的是自定义对象,没有重写equals方法,那么默认使用Object类中的equals方法进行判断,而Object类中equals方法,依赖地址值进行判断。* 需求:如果同姓名和同年龄,就认为是同一个学生。所以,需要在自定义的Javabean类中,重写equals方法就可以了。*/System.out.println(coll.contains(s4));}
public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}public String toString() {return "Student{name = " + name + ", age = " + age + "}";}
}

2.Collection 的遍历方式

在这里插入图片描述
在这里插入图片描述

迭代器遍历

在这里插入图片描述
迭代器不依赖索引
迭代器在Java中的类是 Iterrator ,迭代器是集合专用的遍历方式。
在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {//0.创建集合并添加元素Collection<String> coll = new ArrayList<>();coll.add("aaa");coll.add("bbb");coll.add("ccc");coll.add("ddd");//1.获取迭代器对象Iterator<String> it = coll.iterator();//2.利用循环不断的去获取集合中的每一个元素while (it.hasNext()) {//3.next方法的两件事情:获取元素并移动指针String str = it.next();System.out.println(str);}}

在这里插入图片描述
在这里插入图片描述

增强for遍历

在这里插入图片描述

public static void main(String[] args) {//增强for遍历//0.创建集合并添加元素Collection<String> coll = new ArrayList<>();coll.add("zhangsan");coll.add("lisi");coll.add("wangwu");//1.利用增强for遍历for (String s : coll) {System.out.println(s);}}

在这里插入图片描述

Lambda表达式遍历

在这里插入图片描述

public static void main(String[] args) {//Lambda 表达式遍历//0.创建集合并添加元素Collection<String> coll = new ArrayList<>();coll.add("zhangsan");coll.add("lisi");coll.add("wangwu");//利用匿名内部类的形式/*底层原理:* 其实也会自己遍历集合,依次得到每一个元素* 把得到的每一个元素,传递给下面的accept方法* s 依次表示集合中的每一个的对象 */coll.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});System.out.println("--------------------------");//1.Lambda表达式遍历coll.forEach(s -> System.out.println(s) );}

在这里插入图片描述

3.List集合

在这里插入图片描述

List集合的特有方法

在这里插入图片描述

 public static void main(String[] args) {//0.创建一个集合List<String> list = new ArrayList<>();//1.添加元素list.add("aaa");list.add("bbb");list.add("ccc");//打印集合System.out.println(list); // [aaa, bbb, ccc]System.out.println("-------------------------");//2.在指定位置插入指定的元素list.add(2, "zhangsan");System.out.println(list); // [aaa, bbb, zhangsan, ccc]System.out.println("-------------------------");//3.删除指定索引处的元素,返回被删除的元素/*在调用方法的时候,如果方法出现了重载现象* 优先调用,实参跟形参类型一致的那个方法。*/String remove = list.remove(2);System.out.println(remove); // zhangsanSystem.out.println(list); // [aaa, bbb, ccc]System.out.println("-------------------------");//4.修改指定索引处的元素,返回被修改的元素list.set(0,"狗剩");System.out.println(list); // [狗剩, bbb, ccc]System.out.println("-------------------------");//5.返回指定索引处的元素String s = list.get(1);System.out.println(s); // bbb}
List集合的遍历方式

在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {//0.创建集合并添加元素List<String> list = new ArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");//1.迭代器遍历Iterator<String> it = list.iterator();while (it.hasNext()) {String s = it.next();System.out.println(s);}System.out.println("------------------------");//2.增强forfor (String s : list) {System.out.println(s);}System.out.println("------------------------");//3.Lambda 表达式//匿名内部类list.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});System.out.println("-------------------------");list.forEach(s -> System.out.println(s));System.out.println("------------------------");//4.普通for循环for (int i = 0; i < list.size(); i++) {String s = list.get(i);System.out.println(s);}System.out.println("-------------------------");//5.列表迭代器ListIterator<String> it2 = list.listIterator();while (it2.hasNext()){String s = it2.next();if ("bbb".equals(s)){it2.add("zhangsan");}System.out.println(s);}System.out.println(list); // [aaa, bbb, zhangsan, ccc]}
五种遍历方式对比

在这里插入图片描述

4.数据结构

  • 数据结构:计算机存储、组织数据的方式
  • 不同的业务场景要选择不同的数据结构。
  • 是指数据之间是以什么方式排列在一起的。
  • 数据结构是为了更加方便的管理和使用数据,需要结合具体的业务场景来进行选择。
  • 一般情况下,精心选择的数据结构可以带来更高的运行或者存储效率。
  1. 每种数据结构长什么样子?
  2. 如何添加数据?
  3. 如何删除数据?
    在这里插入图片描述
1).栈

栈的特点:后进先出,先进后出
在这里插入图片描述
在这里插入图片描述

2).队列

队列的特点:先进先出,后进后出
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3)数组

在这里插入图片描述

  • 查询速度快:查询数据通过地址值和索引定位,查询任意数据耗时相同。(元素在内存中是连续存储的)
  • 删除效率低:要将原始数据删除,同时后面每个数据前移。
  • 添加效率极低:添加位置后的每个数据后移,再添加元素。

**数组是一种查询快,增删慢的模型。

4)链表

在这里插入图片描述
在这里插入图片描述

  • 链表中的结点是独立的对象,在内存中是不连续的,每个结点包含数据值和下一个结点的地址。
  • 链表查询慢,无论查询哪个数据都要从头开始找。
  • 链表增删相对快。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
小结

在这里插入图片描述

5)树

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

6)二叉查找树

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

前序遍历:
在这里插入图片描述

中序遍历:
在这里插入图片描述
后序遍历:
在这里插入图片描述
层序遍历:
在这里插入图片描述
在这里插入图片描述

7)平衡二叉树

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

平衡二叉树旋转机制——左旋

就是将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

请添加图片描述

平衡二叉树旋转机制——右旋

就是将根节点的左侧往右拉,左子节点变成了新的父节点,并把多余的右子节点出让,给已经降级根节点当左子节点
在这里插入图片描述
在这里插入图片描述
请添加图片描述
平衡二叉树和二叉查找树对比结构图
在这里插入图片描述

平衡二叉树需要旋转的四种情况
  1. 左左

    • 左左: 当根节点左子树的左子树有节点插入,导致二叉树不平衡

    • 如何旋转: 直接对整体进行右旋即可
      在这里插入图片描述
      在这里插入图片描述

  2. 左右

    • 左右: 当根节点左子树的右子树有节点插入,导致二叉树不平衡
    • 如何旋转: 先在左子树对应的节点位置进行左旋,在对整体进行右旋
      在这里插入图片描述
  3. 右右

    • 右右: 当根节点右子树的右子树有节点插入,导致二叉树不平衡

    • 如何旋转: 直接对整体进行左旋即可
      在这里插入图片描述

  4. 右左

    • 右左:当根节点右子树的左子树有节点插入,导致二叉树不平衡

    • 如何旋转: 先在右子树对应的节点位置进行右旋,在对整体进行左旋

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8)红黑树

在这里插入图片描述
平衡二叉树:

  • 高度平衡
  • 当左右子树高度差超过1时,通过旋转保持平衡

红黑树:

  • 是一个二叉查找树
  • 但是不是高度平衡的
  • 条件:特有的红黑规则

红黑规则

  1. 每一个结点或是红色的,或是黑色的
  2. 根节点必须是黑色
  3. 如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为 Nil ,这些 Nil 视为叶节点,每个叶节点(Nil)是黑色的
  4. 如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
  5. 对每一个结点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
    在这里插入图片描述
    在这里插入图片描述
添加节点的规则

默认颜色:添加节点默认是红色的(效率高

当默认是黑色时:
在这里插入图片描述
当默认是红色时:
在这里插入图片描述
红黑树添加节点后如何保持红黑规则

  • 根节点位置
    • 直接变为黑色
  • 非根节点位置
    • 父节点为黑色
      • 不需要任何操作,默认红色即可
    • 父节点为红色
      • 叔叔节点为红色
        1. 将"父节点"设为黑色,将"叔叔节点"设为黑色
        2. 将"祖父节点"设为红色
        3. 如果"祖父节点"为根节点,则将根节点再次变成黑色
      • 叔叔节点为黑色
        1. 将"父节点"设为黑色
        2. 将"祖父节点"设为红色
        3. 以"祖父节点"为支点进行旋转

在这里插入图片描述
举例:
在这里插入图片描述
跳过添加20、18、23
在这里插入图片描述
在这里插入图片描述
全部添加完成后:
在这里插入图片描述
再向其中添加 15 和 14
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

红黑树增删改查的性能都很好

5.ArrayList集合

在这里插入图片描述

1.ArrayList集合底层原理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.LinkedList集合

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.迭代器底层源码解析

在这里插入图片描述
在这里插入图片描述

6.泛型深入

1)泛型概述

在这里插入图片描述
没有泛型的时候,集合如何存储数据?

public static void main(String[] args) {//没有泛型的时候,集合如何存储数据/*结论:* 如果我们没有给集合指定类型,默认认为所有的数据类型都是Object类型* 此时可以往集合添加任意的数据类型。* 带来一个坏处:我们在获取数据的时候,无法使用它的特有行为。*//*此时推出了泛型 ,可以在添加数据的时候就把类型进行统一。* 而且我们在获取数据的时候,也省的强转了,非常的方便。*///0.创建集合对象ArrayList<Object> list = new ArrayList<>();//1.添加数据list.add(123);list.add("abc");list.add(new Student("zhangsan", 123));//2.遍历集合获取集合中的每一个元素Iterator<Object> it = list.iterator();while (it.hasNext()){Object obj = it.next();//多态的弊端是不能访问子类的特有功能System.out.println(obj);}}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2)泛型类

在这里插入图片描述
在这里插入图片描述

package Generics;import java.util.Arrays;/** 当在编写一个类的时候,如果不确定类型,那么这个类型就可以定义为泛型类。*  */
public class MyArrayList<E> {Object[] obj = new Object[10];int size;public boolean add(E e) {obj[size] = e;size++;return true;}public E get(int index) {return (E) obj[index];}@Overridepublic String toString() {return Arrays.toString(obj);}
}

public static void main(String[] args) {MyArrayList<String> list = new MyArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");System.out.println(list); // [aaa, bbb, ccc, null, null, null, null, null, null, null]MyArrayList<Integer> list2 = new MyArrayList<>();list2.add(123);list2.add(456);list2.add(789);System.out.println(list2); // [123, 456, 789, null, null, null, null, null, null, null]Integer i = list2.get(0);System.out.println(i); //123}

3)泛型方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package Generics;import java.util.ArrayList;public class ListUtil {private ListUtil() {}//类中定义一个静态方法addAll,用来添加多个集合的元素。public static <E> void addAll(ArrayList<E> list, E e1, E e2, E e3, E e4) {list.add(e1);list.add(e2);list.add(e3);list.add(e4);}//添加元素个数未知public static <E> void addAll2(ArrayList<E> list, E...e) {for (E element : e) {list.add(element);}}
}
package Generics;import java.util.ArrayList;public class GenericsDemo3 {//定义一个工具类:ListUtil//类中定义一个静态方法addAll,用来添加多个集合的元素。public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();ListUtil.addAll(list, "aaa", "bbb", "ccc","ddd" );System.out.println(list);//[aaa, bbb, ccc, ddd]ArrayList<Integer> list1 = new ArrayList<>();ListUtil.addAll2(list1,1,2,3,4,5,6,7,8,9,3,6,4,2,5);System.out.println(list1);}
}

4)泛型接口

在这里插入图片描述

package Generics;import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;public class MyArrayList2 implements List<String> {@Overridepublic int size() {return 0;}@Overridepublic boolean isEmpty() {return false;}@Overridepublic boolean contains(Object o) {return false;}@Overridepublic Iterator<String> iterator() {return null;}@Overridepublic Object[] toArray() {return new Object[0];}@Overridepublic <T> T[] toArray(T[] a) {return null;}@Overridepublic boolean add(String s) {return false;}@Overridepublic boolean remove(Object o) {return false;}@Overridepublic boolean containsAll(Collection<?> c) {return false;}@Overridepublic boolean addAll(Collection<? extends String> c) {return false;}@Overridepublic boolean addAll(int index, Collection<? extends String> c) {return false;}@Overridepublic boolean removeAll(Collection<?> c) {return false;}@Overridepublic boolean retainAll(Collection<?> c) {return false;}@Overridepublic void clear() {}@Overridepublic String get(int index) {return null;}@Overridepublic String set(int index, String element) {return null;}@Overridepublic void add(int index, String element) {}@Overridepublic String remove(int index) {return null;}@Overridepublic int indexOf(Object o) {return 0;}@Overridepublic int lastIndexOf(Object o) {return 0;}@Overridepublic ListIterator<String> listIterator() {return null;}@Overridepublic ListIterator<String> listIterator(int index) {return null;}@Overridepublic List<String> subList(int fromIndex, int toIndex) {return null;}
}

public static void main(String[] args) {/*泛型接口的两种使用方式:* 1.实现类给出具体的类型* 2.实现类延续泛型,创建实现类对象时再确定类型 */MyArrayList2 list = new MyArrayList2();list.add("abc");//list.add(123); // java: 不兼容的类型: int无法转换为java.lang.String}

5)泛型的继承和通配符
  • 泛型不具备继承性,但是数据具备继承性
    • 泛型里面写的是什么类型,那么在方法中只能传递什么类型的数据。、

在这里插入图片描述
在这里插入图片描述


在这里插入图片描述

package Generics.Test;public abstract class Animal {/*属性:名字,年龄行为:吃东西*/private String name;private int age;public Animal() {}public Animal(String name, int age) {this.name = name;this.age = age;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}public abstract void eat();public String toString() {return "Animal{name = " + name + ", age = " + age + "}";}
}
package Generics.Test;public abstract class Cat extends Animal{
}
package Generics.Test;public abstract class Dog extends Animal{
}
package Generics.Test;public class PersianCat extends Cat {@Overridepublic void eat() {System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的波斯猫,正在吃小饼干");}
}
package Generics.Test;public class LiHuaCat extends Cat {@Overridepublic void eat() {System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的狸花猫,正在吃鱼");}
}
package Generics.Test;public class HuskyDog extends Dog {@Overridepublic void eat() {System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的哈士奇,正在吃骨头,边吃边拆家");}
}
package Generics.Test;public class TeddyDog extends Dog {@Overridepublic void eat() {System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的泰迪,正在吃骨头,边吃边蹭");}
}
public static void main(String[] args) {/*需求:定义一个继承结构:动物|                           |猫                          狗|      |                    |      |波斯猫   狸花猫                泰迪   哈士奇属性:名字,年龄行为:吃东西波斯猫方法体打印:一只叫做XXX的,X岁的波斯猫,正在吃小饼干狸花猫方法体打印:一只叫做XXX的,X岁的狸花猫,正在吃鱼泰迪方法体打印:一只叫做XXX的,X岁的泰迪,正在吃骨头,边吃边蹭哈士奇方法体打印:一只叫做XXX的,X岁的哈士奇,正在吃骨头,边吃边拆家测试类中定义一个方法用于饲养动物public static void keepPet(ArrayList<???> list){//遍历集合,调用动物的eat方法}要求1:该方法能养所有品种的猫,但是不能养狗要求2:该方法能养所有品种的狗,但是不能养猫要求3:该方法能养所有的动物,但是不能传递其他类型*/ArrayList<PersianCat> list1 = new ArrayList<>();ArrayList<LiHuaCat> list2 = new ArrayList<>();ArrayList<TeddyDog> list3 = new ArrayList<>();ArrayList<HuskyDog> list4 = new ArrayList<>();keepPet(list1);keepPet(list2);keepPet(list3);keepPet(list4);}//要求3:该方法能养所有的动物,但是不能传递其他类型public static void keepPet(ArrayList<? extends Animal> list){}//要求2:该方法能养所有品种的狗,但是不能养猫/*public static void keepPet(ArrayList<? extends Dog> list){}*///要求1:该方法能养所有品种的猫,但是不能养狗/*public static void keepPet(ArrayList<? extends Cat> list){}*/

总结

在这里插入图片描述
在这里插入图片描述

7.Set系列集合

  • 不可以存储重复元素
  • 没有索引,不能使用普通for循环遍历

在这里插入图片描述

  • 无序:存取顺序不一致
  • 不重复:可以去除重复
  • 无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素

Set 集合的实现类

  • HashSet :无序、不重复、无索引
  • LinkedHashSet:有序、不重复、无索引
  • TreeSet:可排序、不重复、无索引
    Set 接口中的方法上基本上与Collection的API一致
    在这里插入图片描述
    在这里插入图片描述
public static void main(String[] args) {/*练习 存储字符串并遍历* 利用Set系列的集合,添加字符串,并使用多种方式遍历* 0.迭代器* 1.增强for* 2.Lambda表达式*///0.创建Set集合的对线Set<String> s = new HashSet<>();//1.添加元素/*如果当前元素是第一次添加,那么可以添加成功,返回true* 如果当前元素是第二次添加,那么添加失败,返回false*/s.add("张三");s.add("李四");s.add("王五");//2.打印集合System.out.println(s); // [李四, 张三, 王五]//迭代器遍历Iterator<String> it = s.iterator();while (it.hasNext()) {String s1 = it.next();System.out.println(s1);}System.out.println("==========================");//增强for遍历for (String s2 : s) {System.out.println(s2);}System.out.println("=========================");//Lambda 表达式/*s.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});*/s.forEach(s3 -> System.out.println(s3));}
1)HashSet

HashSet 底层原理

  • HashSet 集合底层采取哈希表存储数据
  • 哈希表是一种对于增删改查数据性能都较好的结构

哈希表组成

  • JDK8之前:数组+链表
  • JDK8开始:数组+链表+红黑树

哈希值:对象的整数表现形式
在这里插入图片描述哈希值

  • 根据hashCode方法计算出来的int类型的整数
  • 该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算
  • 一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希值
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

public static void main(String[] args) {//0.创建对象Student s1 = new Student("zhangsan", 23);Student s2 = new Student("zhangsan", 23);//1.如果没有重写hashCode方法,不同对象计算处的哈希值是不同的System.out.println(s1.hashCode()); // 990368553System.out.println(s2.hashCode()); // 1096979270//2.如果已经重写hashCode方法,不同的对象只要属性值相同,计算处的哈希值就是一样的System.out.println(s1.hashCode()); // -1461067292System.out.println(s2.hashCode()); // -1461067292//3.但是在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)System.out.println("abc".hashCode()); // 96354System.out.println("acD".hashCode()); // 96354}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {//0.创建学生对象Student s1 = new Student("zhangsan", 23);Student s2 = new Student("lisi", 14);Student s3 = new Student("wangwu", 26);Student s4 = new Student("zhangsan", 23);//1.创建集合用来添加学生HashSet<Student> hs = new HashSet<>();//2.添加数据System.out.println(hs.add(s1)); //trueSystem.out.println(hs.add(s2)); //trueSystem.out.println(hs.add(s3)); //trueSystem.out.println(hs.add(s4)); //falseSystem.out.println(hs);}
package Set;import java.util.Objects;public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}

2)LinkedHashSet

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {//0.创建学生对象Student s1 = new Student("zhangsan", 23);Student s2 = new Student("lisi", 14);Student s3 = new Student("wangwu", 26);Student s4 = new Student("zhangsan", 23);//1.创建集合用来添加学生LinkedHashSet<Student> lhs = new LinkedHashSet<>();//2.添加数据System.out.println(lhs.add(s1)); //trueSystem.out.println(lhs.add(s2)); //trueSystem.out.println(lhs.add(s3)); //trueSystem.out.println(lhs.add(s4)); //falseSystem.out.println(lhs); //[Student{name='zhangsan', age=23}, Student{name='lisi', age=14}, Student{name='wangwu', age=26}]}

在这里插入图片描述

3)TreeSet

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {/*需求:* 存储整数并进行排序 *///0.创建TreeSet集合对象TreeSet<Integer> ts = new TreeSet<>();//1.添加数据ts.add(4);ts.add(5);ts.add(2);ts.add(1);ts.add(3);//2.打印集合System.out.println(ts); // [1, 2, 3, 4, 5]//3.遍历//迭代器Iterator<Integer> it = ts.iterator();while (it.hasNext()) {Integer num = it.next();System.out.println(num);}System.out.println("=================");//加强forfor (Integer t : ts) {System.out.println(t);}System.out.println("======================");//Lambda表达式ts.forEach(num -> System.out.println(num));

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {/*需求:* 创建TreeSet集合,并添加3个学生对象* 学生对象属性:* 姓名、年龄* 要求按照学生的年龄进行排序* 同年龄按照姓名字母排列(暂不考虑中文)* 同姓名,同年龄认为是同一个人** 方式一:* 默认的排序规则/自然排序* Student实现Comparable接口,重写里面的抽象方法,再指定比较规则** 方式二:* 比较器排序* 创建TreeSet对象的时候,传递比较器Comparator指定规则*///0.创建学生对象Student s1 = new Student("zhangsan", 23);Student s2 = new Student("lisi", 24);Student s3 = new Student("wangwu", 25);//1.创建集合对象TreeSet<Student> ts = new TreeSet<>();//2.添加数据ts.add(s2);ts.add(s1);ts.add(s3);//3.打印数据System.out.println(ts);}
package Set;import java.util.Objects;public class Student implements Comparable<Student>{private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic int compareTo(Student o) {int res = this.getAge() - o.getAge();return res;}
}

在这里插入图片描述

 public static void main(String[] args) {/** 需求:请自行选择比较器排序和自然排序两种方式:* 要求:存入四个字符串,c , ab , df , qwer* 按照长度排序,如果一样长则按照首字母排序*///0.创建集合/*o1:表示当前要添加的元素* o2:表示已经在红黑树存在的元素* 返回值:* 负数:认为要添加的元素是小的,存左边* 正数:认为要添加的元素是大的,存右边* 0:认为要添加的元素已经存在,舍弃*//*TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {//按照长度排序int i = o1.length() - o2.length();//如果一样长则按照首字母排序i = i == 0 ? o1.compareTo(o2) : i;return i;}});*/TreeSet<String> ts = new TreeSet<>((o1, o2) -> {//按照长度排序int i = o1.length() - o2.length();//如果一样长则按照首字母排序i = i == 0 ? o1.compareTo(o2) : i;return i;});//添加数据ts.add("c");ts.add("ab");ts.add("df");ts.add("qwer");//打印System.out.println(ts); // [c, ab, df, qwer]}

在这里插入图片描述

package Set;public class Student2 implements Comparable<Student2> {/*属性:(姓名、年龄、语文成绩、数学成绩、英语成绩)*/private String name;private int age;private int Chinese;private int Math;private int English;public Student2() {}public Student2(String name, int age, int Chinese, int Math, int English) {this.name = name;this.age = age;this.Chinese = Chinese;this.Math = Math;this.English = English;}/*** 获取** @return name*/public String getName() {return name;}/*** 设置** @param name*/public void setName(String name) {this.name = name;}/*** 获取** @return age*/public int getAge() {return age;}/*** 设置** @param age*/public void setAge(int age) {this.age = age;}/*** 获取** @return Chinese*/public int getChinese() {return Chinese;}/*** 设置** @param Chinese*/public void setChinese(int Chinese) {this.Chinese = Chinese;}/*** 获取** @return Math*/public int getMath() {return Math;}/*** 设置** @param Math*/public void setMath(int Math) {this.Math = Math;}/*** 获取** @return English*/public int getEnglish() {return English;}/*** 设置** @param English*/public void setEnglish(int English) {this.English = English;}public String toString() {return "Student2{name = " + name + ", age = " + age + ", Chinese = " + Chinese + ", Math = " + Math + ", English = " + English + "}";}/*按照总分从高到低输出到控制台* 如果总分一样,按照语文成绩排* 如果语文一样,按照数学成绩排* 如果数学成绩一样,按照英语成绩排* 如果英语成绩一样,按照年龄排* 如果年龄一样,按照姓名的字母顺序排* 如果都一样,认为是同一个学生,不存*/@Overridepublic int compareTo(Student2 o) {int sum1 = this.getChinese() + this.getMath() + this.getEnglish();int sum2 = o.getChinese() + o.getMath() + o.getEnglish();//比较总分int i = sum1 - sum2;//果总分一样,按照语文成绩排i = i == 0 ? this.getChinese() - o.getChinese() : i;//如果语文一样,按照数学成绩排i = i == 0 ? this.getMath() - o.getMath() : i;//如果数学成绩一样,按照英语成绩排(可以省略不写)i = i == 0 ? this.getEnglish() - o.getEnglish() : i;//如果英语成绩一样,按照年龄排i = i == 0 ? this.getAge() - o.getAge() : i;//如果年龄一样,按照姓名的字母顺序排i = i == 0 ? this.getName().compareTo(o.getName()) : i;return i;}
}
public static void main(String[] args) {/*需求:创建5个学生对象* 属性:(姓名、年龄、语文成绩、数学成绩、英语成绩)* 按照总分从高到低输出到控制台* 如果总分一样,按照语文成绩排* 如果语文一样,按照数学成绩排* 如果数学成绩一样,按照英语成绩排* 如果英语成绩一样,按照年龄排* 如果年龄一样,按照姓名的字母顺序排* 如果都一样,认为是同一个学生,不存。*///0.创建5个学生对象Student2 s1 = new Student2("zhangsan", 23, 90, 99, 50);Student2 s2 = new Student2("lisi", 24, 90, 98, 50);Student2 s3 = new Student2("wangwu", 25, 95, 100, 30);Student2 s4 = new Student2("zhaoliu", 26, 60, 99, 70);Student2 s5 = new Student2("qianqi", 26, 70, 80, 70);//1.创建集合TreeSet<Student2> ts = new TreeSet<>();//2.添加数据ts.add(s1);ts.add(s2);ts.add(s3);ts.add(s4);ts.add(s5);//3.打印//System.out.println(ts);Iterator<Student2> it = ts.iterator();while (it.hasNext()) {Student2 info = it.next();int sum = info.getChinese() + info.getMath() + info.getEnglish();System.out.println(info + " 总分:" + sum);}/*Student2{name = qianqi, age = 26, Chinese = 70, Math = 80, English = 70} 总分:220Student2{name = wangwu, age = 25, Chinese = 95, Math = 100, English = 30} 总分:225Student2{name = zhaoliu, age = 26, Chinese = 60, Math = 99, English = 70} 总分:229Student2{name = lisi, age = 24, Chinese = 90, Math = 98, English = 50} 总分:238Student2{name = zhangsan, age = 23, Chinese = 90, Math = 99, English = 50} 总分:239*/}

在这里插入图片描述

8.单列集合使用场景

在这里插入图片描述
在这里插入图片描述

相关文章:

十三、集合进阶——单列集合 及 数据结构

单列集合 及 数据结构 13.1 集合体系结构13.1.2 单列集合1. Collection2.Collection 的遍历方式迭代器遍历增强for遍历Lambda表达式遍历 3.List集合List集合的特有方法List集合的遍历方式五种遍历方式对比 4.数据结构1).栈2).队列3&#xff09;数组4&#xff09;链表小结5&…...

Android | ArcGIS入门

一、概述 ArcGIS是由Esri开发的地理信息系统&#xff08;GIS&#xff09;软件。它用于制图、空间分析和数据可视化。ArcGIS允许用户以各种格式创建、管理、分析和共享地理信息。它通常用于城市规划、环境管理和应急响应等领域。该软件包括一系列工具&#xff0c;用于创建地图、…...

dockerfile文件书写

1.dockerfile构建nginx镜像 1.1书写dockerfile文件 mkdir nginx #创建nginx目录 cd nginx vim dockerfile # 修改文件FROM centos # 基础镜像&#xff0c;默认最新的centos8操作系统 MAINTAINER xianchao # 指定镜像的作者信息 RUN rm -rf /etc/yum.repos.d/* # centos8默认…...

蓝桥杯-整数删除

给定一个长度为 N 的整数数列&#xff1a;A1, A2, ... , AN。你要重复以下操作 K 次&#xff1a; 每次选择数列中最小的整数&#xff08;如果最小值不止一个&#xff0c;选择最靠前的&#xff09;&#xff0c;将其删除。 并把与它相邻的整数加上被删除的数值。 输出 K 次操作后…...

以程序员的视角,看前后端分离的是否必要?

Hello&#xff0c;我是贝格前端工场&#xff0c;本篇分享一个老生常谈的话题&#xff0c;前后端分离是必然趋势&#xff0c;但也是要区分具体的场景&#xff0c;欢迎探讨&#xff0c;关注&#xff0c;有前端开发需求可以私信我&#xff0c;上车了。 一、什么是前后端分离和不分…...

Linux:sed进阶(12)

Linux&#xff1a;shell脚本&#xff1a;基础使用&#xff08;5&#xff09;《正则表达式-sed工具》_linux脚本表达式s-CSDN博客https://blog.csdn.net/w14768855/article/details/132347574?ops_request_misc%257B%2522request%255Fid%2522%253A%252217084222871680019707523…...

Linux命令-builtin命令(执行bash内建命令)

说明 用于执行指定的bash内建命令。builtin 命令调用的bash内建命令优先于同名的外部命令及同名的shell函数。 语法 builtin [shell-builtin [arg ...]]参数 shell-builtin&#xff08;可选&#xff09;&#xff1a;要调用的bash内建命令。 arg&#xff08;可选&#xff09…...

HTML的特殊字符

HTML的特殊字符 有些特殊的字符在 html 文件中是不能直接表示的&#xff0c;例如: 空格&#xff0c;小于号(<)&#xff0c;大于号(>)&#xff0c;按位与(&)。 空格 示例代码&#xff1a; 运行结果&#xff1a; 由于html 标签就是用 < > 表示的&#xff0…...

内核移植学习

内核移植 内核移植就是指将RT-Thread内核在不同的芯片架构、不同的板卡上运行起来。 移植可分为CPU架构移植和BSP板级支持包移植两部分。 CPU架构移植 在嵌入式领域有多种不同CPU架构&#xff0c;例如Cortex-M、ARM920T、MIPS32、RISC-V等等。 为了使RT-Thread能够在不同C…...

Mysql 两个日期相减得到指定的格式数据

首先避坑&#xff1a; Mysql 中两个日期直接相减&#xff0c;若在同一天则得到的是秒&#xff0c;否则相减得到的并不是秒&#xff0c;一定要注意。 函数 TIMESTAMPDIFF(unit,begin,end); 函数返回 begin - end 的结果。 其中 begin 和 end 是 DATE 或 DATETIME 表达式。 …...

第六十四天 服务攻防-框架安全CVE复现Apache shiroApache Solr

第六十四天 服务攻防-框架安全&CVE复现Apache shiro&Apache Solr 知识点: 中间件及框架列表: IIS,Apache,Nginx,Tomcat,Docker,K8s,Weblogic.JBoos,WebSphere, Jenkins,GlassFish,Jetty,Jira,Struts2,Laravel,Solr,Shiro,Thinkphp,Spring, Flask,jQuery等 1、开发框…...

JavaScript 设计模式之享元模式

享元 将一部分共用的方法提取出来作为公用的模块 const Car {getName: function () {return this.name},getPrice: function (price) {return price * 30} }const BMW function (name, price) {this.name namethis.price price } BMW.prototype Car const bmw new BMW(…...

利用故事推动企业变革:如何提升数据分析技能

单一的数据和表格尽管有算法的支撑&#xff0c;但在其表达方式上总会让人感到头疼。当我们需要深入了解企业的盈利能力&#xff0c;或是尝试评估业务的增长机会时&#xff0c;以往都会将精力全部放在分析数字、阅读信息、回顾历史和沟通交流之上&#xff0c;却忽略随之而生成的…...

Python内置函数04——enumerate

文章目录 概述语法实例展示 概述 在Python中&#xff0c;enumerate()是一个很常用的内置函数。它的作用是将一个可迭代对象&#xff08;如列表、元组、字符串等&#xff09;组合为一个索引序列和元素序列的枚举对象。 语法 enumerate(iterable, start0) 其中&#xff0c;ite…...

unity学习(28)——登录功能

有之前注册的知识&#xff0c;登录就很容易处理了。 登陆成功返回id&#xff1a; 登录失败返回null&#xff1a; 测试同一账号不能重复登陆&#xff01;登录成功后最好可以跳到新的场景中 结果是好的&#xff0c;去服务器看一下对应部分的代码&#xff0c;可见&#xff0c;登…...

Mac公证脚本-Web公证方式

公证方式 Mac 公证方式有三种 公证方法 优点 缺点 阐述 Xcode Xcode携带的图形界面&#xff0c;使用方便 无法进行自动化公证 单个App应用上架使用较多 altool&#xff08;旧版&#xff09; 支持pkg&#xff0c;dmg&#xff0c;脚本自动化 2023/11/01 将会过期 已经…...

让你专注工作的思维模板,进入每天的专注生活

开启专注生活&#xff0c;打造高效氛围&#xff0c;踏上传奇之路。 如何专注工作&#xff1f; 阻止内部干扰阻止外部干扰结论 专注象限图如下&#xff1a;&#xff08;幸福是一种不断增加难度的活动&#xff09; A1是你开始做某事的时候。 A2是当任务变得过于简单的时候。 A3是…...

Java之获取Nginx代理之后的客户端IP

Java之获取Nginx代理之后的客户端IP Nginx代理接口之后&#xff0c;后台获取的IP地址都是127.0.0.1&#xff0c;解决办法是需要配置Nginx搭配后台获取的方法&#xff0c;获得设备的真实地址。我们想要获取的就是nginx代理日志中的这个IP nginx配置 首先在nginx代理的对应lo…...

【springboot+vue项目(十五)】基于Oauth2的SSO单点登录(二)vue-element-admin框架改造整合Oauth2.0

Vue-element-admin 是一个基于 Vue.js 和 Element UI 的后台管理系统框架&#xff0c;提供了丰富的组件和功能&#xff0c;可以帮助开发者快速搭建现代化的后台管理系统。 一、基本知识 &#xff08;一&#xff09;Vue-element-admin 的主要文件和目录 vue-element-admin/ |…...

音频的传输链路与延迟优化点

麦克风->系统采集模块->APP采集模块->3A、混响等音效->混音->音频编码->RTC网络发送-> MediaServer->RTC网络接收->音频jitter buffer->音频解码->音频的后处理(均衡)->APP播放模块->x系统播放模块->扬声器/耳机。 整个链路如上&a…...

【51单片机】直流电机驱动(PWM)(江科大)

1.直流电机介绍 直流电机是一种将电能转换为机械能的装置。一般的直流电机有两个电极,当电极正接时,电机正转,当电极反接时,电机反转 直流电机主要由永磁体(定子)、线圈(转子)和换向器组成 除直流电机外,常见的电机还有步进电机、舵机、无刷电机、空心杯电机等 2.电机驱动…...

腾讯文档(excel也一样)设置单元格的自动行高列宽

1. 选中单元格 可选择任意一个或者几个 2. 设置自动 行高和列宽 即可生效...

vue-router 提供的几种导航守卫

vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入路由导航中&#xff1a;全局的&#xff0c;单个路由独享的&#xff0c;或者组件级的。 1、全局前置守卫​ 你可以使用 router.beforeEach 注册一个全局前置守卫&#xff1a; const route…...

Element UI 组件的安装及使用

Element UI 组件的安装及使用 Element UI 是一套基于 Vue.js 的桌面端 UI 组件库&#xff0c;提供了丰富的、高质量的 UI 组件&#xff0c;可以帮助开发者快速构建用户界面。 1、安装 Element UI 使用 npm 安装 npm install element-ui -S2、使用 CDN 安装 在 HTML 页面中引…...

网站架构演变、LNP+Mariadb数据库分离、Web服务器集群、Keepalived高可用

目录 day02 深入理解程序的数据存储 验证 配置NFS服务器 配置代理服务器 配置名称解析 day02 深入理解程序的数据存储 程序将文字数据保存到数据库中程序将非文字数据&#xff08;如图片、视频、压缩包等&#xff09;保存到相应的文件目录中 验证 发一篇文章&#xf…...

设计模式(七):策略模式(行为型模式)

FullDiscount Strategy&#xff0c;策略模式&#xff1a;定义一系列的算法&#xff0c;把他们一个个封装起来&#xff0c; 并使他们可以互相替换&#xff0c;本模式使得算法可以独立于使用它们的客户。 场景&#xff1a;购物车结算时&#xff0c;根据不同的客户&#xff0c;…...

人工智能|深度学习——基于对抗网络的室内定位系统

代码下载&#xff1a; 基于CSI的工业互联网深度学习定位.zip资源-CSDN文库 摘要 室内定位技术是工业互联网相关技术的关键一环。该技术旨在解决于室外定位且取得良好效果的GPS由于建筑物阻挡无法应用于室内的问题。实现室内定位技术&#xff0c;能够在真实工业场景下实时追踪和…...

MySQL的配置文件my.cnf正常的配置项目

my.cnf&#xff08;或my.ini&#xff09;是MySQL的配置文件&#xff0c;其中包含了多种设置&#xff0c;用于控制MySQL服务器的运行方式。以下是my.cnf中一些常见的配置项目&#xff1a; 服务器设置 - [mysqld]&#xff1a;服务器的配置部分。 - user&#xff1a;指定M…...

小程序API能力集成指南——界面导航栏API汇总

ty.setNavigationBarColor 设置页面导航条颜色 需引入MiniKit&#xff0c;且在>2.0.0版本才可使用 参数 Object object 属性类型默认值必填说明frontColorstring是前景颜色值&#xff0c;包括按钮、标题、状态栏的颜色&#xff0c;仅支持 #ffffff 和 #000000backgroundCo…...

onlyoffice基础环境搭建+部署+demo可直接运行 最简单的入门

office这个体系分为四个大教程 1、【document server文档服务器基础搭建】 2、【连接器(connector)或者jsApi调用操作office】-进阶 3、【document builder文档构造器使用】-进阶 4、【Conversion API(文档转化服务)】-进阶 如果需要连接器&#xff0c;可以查看&#xff1a;onl…...