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

2024-02-21 11:52

本文主要是介绍十三、集合进阶——单列集合 及 数据结构,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

单列集合 及 数据结构

  • 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.chinasem.cn/article/731694

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

uva 11178 计算集合模板题

题意: 求三角形行三个角三等分点射线交出的内三角形坐标。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

[MySQL表的增删改查-进阶]

🌈个人主页:努力学编程’ ⛅个人推荐: c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构,刷题刻不容缓:点击一起刷题 🌙心灵鸡汤:总有人要赢,为什么不能是我呢 💻💻💻数据库约束 🔭🔭🔭约束类型 not null: 指示某列不能存储 NULL 值unique: 保证某列的每行必须有唯一的值default: 规定没有给列赋值时的默认值.primary key:

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。

《数据结构(C语言版)第二版》第八章-排序(8.3-交换排序、8.4-选择排序)

8.3 交换排序 8.3.1 冒泡排序 【算法特点】 (1) 稳定排序。 (2) 可用于链式存储结构。 (3) 移动记录次数较多,算法平均时间性能比直接插入排序差。当初始记录无序,n较大时, 此算法不宜采用。 #include <stdio.h>#include <stdlib.h>#define MAXSIZE 26typedef int KeyType;typedef char In

从0到1,AI我来了- (7)AI应用-ComfyUI-II(进阶)

上篇comfyUI 入门 ,了解了TA是个啥,这篇,我们通过ComfyUI 及其相关Lora 模型,生成一些更惊艳的图片。这篇主要了解这些内容:         1、哪里获取模型?         2、实践如何画一个美女?         3、附录:               1)相关SD(稳定扩散模型的组成部分)               2)模型放置目录(重要)