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

news/发布时间2024/5/15 12:33:57

单列集合 及 数据结构

  • 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.单列集合使用场景

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

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

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

相关文章

Cubase学习:Cubase 12常用快捷键

按键盘上的上下箭头就可以让选中的音符向上或向下移动 数字0键: 停止 Ctrl+数字 0 键: 新建视图层 Alt+数字0 键: 重新设置视图层 小数点键: 播放指针回零点 数字1 键: 左定位指针 数字 2 键: 右定位指针 数字3 键--数字9键: 分别控制 3--9 的7个定位标志 Alt+数字1 键--数字9键…

Git使用

相关链接 【C#】编号生成器&#xff08;定义单号规则、固定字符、流水号、业务单号&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/129129787 【C#】最全单据打印&#xff08;打印模板、条形码&二维码、字体样式、项目源码&#x…

数据分析(二)自动生成分析报告

1. 报告生成思路概述 怎么快速一份简单的数据分析报告&#xff0c;注意这个报告的特点&#xff1a; --网页版&#xff0c;可以支持在线观看或者分享HTML文件 --标题&#xff0c;动图&#xff0c;原始数据应有尽有 --支持交互&#xff0c;比如plotly交互画面&#xff0c;数据…

相机姿态slovePnP

opencv slovePnP 物体的姿态 估计 物体的姿态&#xff08;位置和方向&#xff09; 通过已知的图像坐标点数组&#xff0c;和对应的世界坐标点数组&#xff0c;相机的内参&#xff0c;畸变参数&#xff0c;求解相机姿态&#xff0c;即旋转向量和平移向量&#xff0c; 例如&…

Linux之ACL权限chmod命令

一. chmod命令 chmod命令来自英文词组change mode的缩写&#xff0c;其功能是改变文件或目录权限的命令。默认只有文件的所有者和管理员可以设置文件权限&#xff0c;普通用户只能管理自己文件的权限属性。 设置权限时可以使用数字法&#xff0c;亦可使用字母表达式&#xff0…

CSRF靶场实战

DVWA靶场链接&#xff1a;https://pan.baidu.com/s/1eUlPyB-gjiZwI0wsNW_Vkw?pwd0b52 提取码&#xff1a;0b52 DVWA Low 级别打开靶场&#xff0c;修改密码 复制上面的 url&#xff0c;写个简单的 html 文件 <html <body> <a hrefhttp://127.0.0.1/DVWA/vulne…

【论文解读】transformer小目标检测综述

目录 一、简要介绍 二、研究背景 三、用于小目标检测的transformer 3.1 Object Representation 3.2 Fast Attention for High-Resolution or Multi-Scale Feature Maps 3.3 Fully Transformer-Based Detectors 3.4 Architecture and Block Modifications 3.6 Improved …

链表和顺序表的优劣分析及其时间、空间复杂度分析

链表和顺序表的优劣分析及其时间、空间复杂度分析 一、链表和顺序表的优劣分析二、算法复杂度<font face "楷体" size 5 color blue>//上面算法的执行次数大致为&#xff1a;F&#xff08;N&#xff09; N^22*N10;   N 10,F(10) 1002010 130次   N 1…

C++基础知识(六:继承)

首先我们应该知道C的三大特性就是封装、继承和多态。 此篇文章将详细的讲解继承的作用和使用方法。 继承 一个类&#xff0c;继承另一个已有的类&#xff0c;创建的过程 父类(基类)派生出子类(派生类)的过程 继承提高了代码的复用性 【1】继承的格式 class 类名:父类名 {}; 【…

深入浅出:探究过完备字典矩阵

在数学和信号处理的世界里&#xff0c;我们总是在寻找表达数据的最佳方式。在这篇博文中&#xff0c;我们将探讨一种特殊的矩阵——过完备字典矩阵&#xff0c;这是线性代数和信号处理中一个非常有趣且实用的概念。 什么是过完备字典矩阵&#xff1f; 首先&#xff0c;我们先…

消息中间件篇之RabbitMQ-信息堆积

一、信息堆积 当生产者发送消息的速度超过了消费者处理消息的速度&#xff0c;就会导致队列中的消息堆积&#xff0c;直到队列存储消息达到上限。之后发送的消息就会成为死信&#xff0c;可能会被丢弃&#xff0c;这就是消息堆积问题。 解决消息堆积有三种种思路&#xff1a; 1…

精品基于SpringBoot的体育馆场地预约赛事管理系统的设计与实现-选座

《[含文档PPT源码等]精品基于SpringBoot的体育馆管理系统的设计与实现[包运行成功]》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; Java——涉及技术&#xff1a; 前端使用技术&#…

StarRocks——滴滴OLAP的技术实践与发展方向

原文大佬的这篇StarRocks实践文章整体写的很深入&#xff0c;介绍了StarRocks数仓架构设计、物化视图加速实时看板、全局字典精确去重等内容&#xff0c;这里直接摘抄下来用作学习和知识沉淀。 目录 一、背景介绍 1.1 滴滴OLAP的发展历程 1.2 OLAP引擎存在的痛点 1.2.1 运维…

[ 2024春节 Flink打卡 ] -- 优化(draft)

2024&#xff0c;游子未归乡。工作需要&#xff0c;flink coding。觉知此事要躬行&#xff0c;未休&#xff0c;特记 资源配置调优内存设置 TaskManager内存模型 https://nightlies.apache.org/flink/flink-docs-release-1.18/docs/deployment/config/ TaskManager 内存模型…

『SD』零基础快速搭建Stable Diffusion(Windows版)

theme: smartblue 点赞 关注 收藏 学会了 本文简介 本文介绍如何在 Windows 安装 Stable Diffusion WebUI&#xff0c;不需要懂代码&#xff0c;只要跟着本文一步步操作就能在你电脑用AI绘画了。 只需3步&#xff1a; 安装 Python &#xff0c;版本需要大于 3.10安装 Stable…

在autodl搭建stable-diffusion-webui+sadTalker

本文介绍在autodl.com搭建gpu服务器&#xff0c;实现stable-diffusion-webuisadTalker功能&#xff0c;图片音频 可生成视频。 autodl租GPU 自己本地部署SD环境会遇到各种问题&#xff0c;网络问题&#xff08;比如huggingface是无法访问&#xff09;&#xff0c;所以最好的方…

idm直链怎么用 IDM直链下载风险 Internet Download Manager下载 idm官网登录 idm直链提取

作为一款备受好评的下载加速器&#xff0c;idm几乎可以胜任所有的下载场景。无论是直链资源、磁力链接还是种子文件&#xff0c;idm均能把它们高速下载到本地保存。并且&#xff0c;理论上idm可以将下载速度提高3至5倍。有关idm直链怎么用&#xff0c;IDM直链下载风险的相关问题…

网络编程、UDP、TCP

计算机网络 就是将地理位置不同的具有独立功能的多台计算及外部设备&#xff0c;通过通信线路连接起来&#xff0c;在网络操作系统、网络管理软件以及网络通信协议的管理和协调下&#xff0c;实现资源共享和信息传递的计算机系统 目的 传播交流信息、数据交换、通信 如何做…

【Ubuntu】解决Ubuntu 22.04开机显示器颜色(高对比度/反色)异常的问题

使用Ubuntu 22.04时强制关机了一下&#xff08;make -j16把电脑搞崩了&#xff09;&#xff0c;开机后系统显示的颜色异常&#xff0c;类似高对比度或反色&#xff0c;如下图。看着很难受&#xff0c;字体也没办法辨认。还好之前遇到过类似的问题&#xff0c;应该是一个配置文件…

【C语言】linux内核ipoib模块 - ipoib_ib_post_receive

一、中文注释 用于以太网接口&#xff08;InfiniBand&#xff09;上的IP over IB&#xff08;IPoIB&#xff09;设备的Linux内核函数&#xff0c;负责将接收缓冲区&#xff08;一个包&#xff09;提交到网络设备的队列中等待数据到达。下面是中文注释版本的函数代码&#xff1…
推荐文章