学习笔记22 set

news2024/11/16 21:42:00

一、概述

Set是一种集合类型,可以快速在大量数据中查找特定值。

Set存储无序序列中的元素,并且不允许重复。与列表不同,列表中的数据可以通过索引访问,但是在集合中,元素没有与集合中的位置相关联。

Set是优化了搜索特定元素的数据结构,是查找特定元素时比较适用的一种集合类型。Set与List的区别是,Set不允许重复元素,而且不能在指定位置插入元素

二、hashset(无顺序)

1.概念

HashSet是Set接口的一个具体实现,它使用哈希码(hash codes)将元素存储在集合中,从而加快搜索速度。

哈希码是一个整数值,代表一个对象的特征,有些类似于识别码(但不一定是唯一的)。使用哈希算法可以为对象计算哈希码。理想情况下,不同的对象产生的哈希码不同,相同对象的哈希码相同。

Java中的每个对象都有一个hashCode方法,其返回一个哈希码。然而,从Object类继承的hashCode方法通常不够用,因为它返回的值基于对象的内存地址,而不是对象的值,可能会有相同值的不同对象返回不同的哈希码。因此,通常需要重写hashCode方法,以返回等价对象的相同哈希码。

当向HashSet中添加一个对象时,HashSet会调用该对象的hashCode方法获取其哈希码,并检查集合中是否已经存在具有相同哈希码的对象。如果已经存在,则调用该对象的equals方法进一步判断两个对象是否相等。如果相等,则HashSet不会将该对象添加到集合中。

为啥检查过hash code还要用equal判断是否相等呢?因为哈希算法可能会存在冲突,即不同的对象可能会产生相同的哈希码,因此HashSet在判断对象是否相等时,同时使用hashCode方法和equals方法进行判断。如果一个新对象的哈希码与集合中已有的对象的哈希码相同,但是两个对象的值不同,HashSet会允许该新对象添加到集合中。

在HashSet中,每个对象的哈希码对应着一个桶(bucket),所有具有相同哈希码的对象都被存储在相同哈希码的桶中。有些桶中只存储一个对象,而其他桶中则可能存储多个对象。

Load factor是指哈希表中需要被占用的桶(buckets)的百分比,在这个百分比被占用时,哈希表的容量将会被增加。例如,如果一个哈希表的load factor为0.75,那么当75%的桶被占用时,哈希表的容量就会被增加。

2.构造器

3.add方法 

import java.util.*;

/**
 * This program demonstrates how to add elements to a HashSet.
 * It also shows that duplicate elements are not allowed.
 */
public class HashSetDemo1 {
    public static void main(String[] args) {
        // Create a HashSet to hold String objects.
        Set<String> fruitSet = new HashSet<>();

        // Add some strings to the set.
        fruitSet.add("Apple");
        fruitSet.add("Banana");
        fruitSet.add("Pear");
        fruitSet.add("Strawberry");

        // Display the elements in the set.
        System.out.println("Here are the elements.");
        System.out.println(fruitSet);

        // Try to add a duplicate element.
        System.out.println("\nTrying to add Banana to the set again . . .");
        if (!fruitSet.add("Banana")) {
            System.out.println("Banana was not added again.");
        }

        // Display the elements in the set.
        System.out.println("\nHere are the elements once more.");
        System.out.println(fruitSet);
    }
}
Here are the elements.
[Apple, Pear, Strawberry, Banana]
Trying to add Banana to the set again...
Banana was not added again.
Here are the elements once more.
[Apple, Pear, Strawberry, Banana]

HashSet类的add方法在添加重复项时不会抛出异常,只是不会添加该项。但是该方法会返回一个布尔值,指示该项是否已添加。上面的语句调用了add方法,将"Banana"作为参数传递。由于"Banana"已经在集合中,该方法返回false,表示没有再次添加它。 

4.自己的hashCode Method

有时候我们不希望用object类的hashcode方法,希望重写hashcode方法,需要注意:

1.如果多次调用一个对象的hashCode方法,该方法应始终返回相同的值。
2. 如果equals方法报告两个对象相等,则两个对象的hashCode方法都应该返回相同的值。
3. 如果equals方法报告两个对象不相等,则两个对象具有相同的哈希码是允许的。但不能有太多不相等的对象具有相同的哈希码,因为这样会降低使用哈希码进行搜索的算法的性能。

下面看个例子,这个例子中我们重写了equals方法,但没有重写hashcode 方法,因为这里不可能多次调用  值相同 的 不同对象,也就是说:如果对象A B的值相同,那么B对象一定就是A对象(不可能是和A对象值相同的另一个对象,地址和对象是一一对应的,相同的对象不可能有多个地址),既 B对象的地址就是A对象的地址,所以我们可以使用默认的hashcode 方法。

public class Car {
    private String vin;         // 车辆识别号
    private String description; // 车辆描述
    
    /**
     * 构造函数
     * @param v VIN
     * @param desc 车辆描述
     */
    public Car(String v, String desc) {
        vin = v;
        description = desc;
    }
    
    /**
     * 获取车辆识别号
     */
    public String getVin() {
        return vin;
    }
    
    /**
     * 获取车辆描述
     */
    public String getDescription() {
        return description;
    }
    
    /**
     * 返回包含VIN和描述的字符串
     */
    public String toString() {
        return "VIN:" + vin + "\tDescription:" + description;
    }
    
    /**
     * 返回此车辆的哈希码
     */
    public int hashCode() {
        return vin.hashCode();
    }
    
    /**
     * 比较两个对象是否相等
     */
    public boolean equals(Object obj) {
        if (obj == null || !(obj instanceof Car))
            return false;
        else {
            Car tempCar = (Car) obj;
            return vin.equalsIgnoreCase(tempCar.vin);
        }
    }
}
import java.util.*;

public class CarHashSet {
    public static void main(String[] args) {
        // 创建一个HashSet用于存储Car对象
        Set<Car> carSet = new HashSet<>();

        // 向HashSet中添加一些Car对象
        carSet.add(new Car("227H54", "1997 Volkswagen"));
        carSet.add(new Car("448A69", "1965 Mustang"));
        carSet.add(new Car("453B55", "2007 Porsche"));
        carSet.add(new Car("177R60", "1980 BMW"));

        // 打印HashSet中的元素
        System.out.println("Here are the cars in the set:");
        for (Car c : carSet) {
            System.out.println(c);
        }
        System.out.println();

        // 搜索一个特定的车辆。这个车辆在集合中。
        Car mustang = new Car("448A69", "1965 Mustang");
        System.out.println("Searching for " + mustang);
        if (carSet.contains(mustang)) {
            System.out.println("The Mustang is in the set.");
        } else {
            System.out.println("The Mustang is NOT in the set.");
        }

        // 搜索另一辆车。这辆车不在集合中。
        Car plymouth = new Car("911C87", "2000 Plymouth");
        System.out.println("Searching for " + plymouth);
        if (carSet.contains(plymouth)) {
            System.out.println("The Plymouth is in the set.");
        } else {
            System.out.println("The Plymouth is NOT in the set.");
        }
    }
}
Here are the names in the set.
Chris
Katherine
David
Kenny
Katherine is in the set.
Bethany is NOT in the set.

三、LinkedHashSet Class(根据传入的顺序排序)

你可能已经注意到HashSet元素显示的顺序与它们添加到集合中的顺序不匹配。集合没有元素的内部位置概念,也不会跟踪插入的顺序。当您遍历一个HashSet时,不应该期望迭代器按照它们插入的顺序返回元素。

如果您需要按照插入的顺序访问集合元素,则可以使用LinkedHashSet类而不是HashSet。LinkedHashSet类是HashSet的扩展,它保持一个内部链接列表,引用按照它们被插入的顺序排列的集合元素。这使您能够按照插入的顺序遍历集合。

四、 TreeSet Class(根据key的大小排序)

tree set会按大小顺序存放element。而这里的大小顺序指的是 “1小于2” 或 实现了Comparable interface的对象。

如果我们使用TreeSet的无参数构造器,TreeSet会自动进行排序。

当然,对于没有实现Comparable interface的对象,如果我们可以修改这个对象的代码,那么我们可以让这个对象实现Comparable interface;如果我们不能修改这个对象本身,我们也可以让这个对象实现Comparator interface ,也就是创建一个ComparatorComparator接受两个参数,然后进行比较。

 Comparator interface:

 对于之前的car例子,如果我们希望按照vin顺序来排序车辆:

import java.util.Comparator;

public class CarComparator implements Comparator<Car> {
    public int compare(Car car1, Car car2) {
        // 获取两个车辆的VIN
        String vin1 = car1.getVin();
        String vin2 = car2.getVin();

        // 比较VIN并返回比较结果
        return vin1.compareToIgnoreCase(vin2);
    }
}

 注意,这里我们没有实现Comparator的equal方法,所以我们就会自动地调用object类的equal方法(通过地址比较)。

import java.util.*;

public class TreeSetDemo2 {
    public static void main(String[] args) {
        // 创建一个TreeSet并将CarComparator的实例传递给它
        SortedSet<Car> carSet = new TreeSet<>(new CarComparator());

        // 将一些Car对象添加到TreeSet中
        carSet.add(new Car("227H54", "1997 Volkswagen"));
        carSet.add(new Car("453B55", "2007 Porsche"));
        carSet.add(new Car("177R60", "1980 BMW"));
        carSet.add(new Car("448A69", "1965 Mustang"));

        // 打印按VIN顺序排序的TreeSet中的元素
        System.out.println("Here are the cars sorted in order of their VINs:");
        for (Car car : carSet) {
            System.out.println(car);
        }
    }
}

Here are the cars sorted in order of their VINs:

VIN: 177R60 Description: 1980 BMW

VIN: 227H54 Description: 1997 Volkswagen

VIN: 448A69 Description: 1965 Mustang

VIN: 453B55 Description: 2007 Porsche

treeSet构造器:

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

消息队列总结(4)- RabbitMQ Kafka RocketMQ高性能方案

1.RabbitMQ的高性能解决方案 1.1 发布确认机制 RabbitMQ提供了3种生产者发布确认的模式&#xff1a; 简单模式&#xff08;Simple Mode&#xff09;&#xff1a;生产者发送消息后&#xff0c;等待服务器确认消息已经被接收。这种模式下&#xff0c;生产者发送消息后会阻塞&am…

M5ATOMS3基础03给ROS1发一个问候(rosserial)

引出问题 关于之前2020年的博客&#xff1a; 01. ESP8266和ROS调试一些问题汇总 02. ESP8266和ESP32配置&#xff08;需使用ROS1和ROS2&#xff09; 效果展示 使用M5ATOMS3与ROS1&#xff08;kinetic&#xff0c;melodic&#xff0c;noetic&#xff09;版本通信比较通用的是…

BUU [网鼎杯 2020 朱雀组]phpweb

BUU [网鼎杯 2020 朱雀组]phpweb 众生皆懒狗。打开题目&#xff0c;只有一个报错&#xff0c;不知何从下手。 翻译一下报错&#xff0c;data()函数:,还是没有头绪&#xff0c;中国有句古话说的好“遇事不决抓个包” 抓个包果然有东西&#xff0c;仔细一看这不就分别是函数和参…

【算法基础:贪心】6. 贪心

文章目录 区间问题905. 区间选点&#xff08;排序 贪心&#xff09;908. 最大不相交区间数量&#xff08;排序 贪心&#xff09;906. 区间分组&#xff08;排序 优先队列 贪心&#xff09;⭐907. 区间覆盖&#xff08;排序 贪心&#xff09; Huffman树148. 合并果子&#…

【LeetCode 75】第十四题(643)子数组最大平均数

题目: 示例: 分析: 给一个数组,问数组里长度为k的连续数组中的最大平均值是多少. 这题已经把意思说的很明白了,并且连子数组的长度都固定了,并且是连续的,这里可以直接使用固定长度的滑动窗口来计算. 用两个指针来在数组里划定一个长度为k的范围,然后计算指针范围内的平均数…

数组传参,指针传参

文章目录 一维数组传参二维数组传参一级指针传参二级指针传参 一维数组传参 二维数组传参 一级指针传参 二级指针传参

CentOS 8 上安装 Nginx

Nginx是一款高性能的开源Web服务器和反向代理服务器&#xff0c;以其轻量级和高效能而广受欢迎。在本教程中&#xff0c;我们将学习在 CentOS 8 操作系统上安装和配置 Nginx。 步骤 1&#xff1a;更新系统 在安装任何软件之前&#xff0c;让我们先更新系统的软件包列表和已安…

【树链剖分+MST】CF609E

Problem - E - Codeforces 题意&#xff1a; 思路&#xff1a; 先把全局的MST求出来&#xff0c;然后对于一条边&#xff0c;如果它本来就在MST中&#xff0c;说明代价就是MST的权值和&#xff0c;否则它加入MST中&#xff0c;此时MST形成了环&#xff0c;我们把环中最大的那…

深入探究Java面向对象的三大特征:封装、继承、多态

文章目录 1. 封装&#xff08;Encapsulation&#xff09;2. 继承&#xff08;Inheritance&#xff09;3. 多态&#xff08;Polymorphism&#xff09;结语 导语&#xff1a;Java是一门面向对象的编程语言&#xff0c;其核心思想是将现实世界中的事物抽象成对象&#xff0c;并通过…

Python(五十二)列表元素的判断及遍历

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

自己整理的JAVA集合

概括&#xff1a; 数组&#xff0c;链表&#xff0c;散列表&#xff0c;二分查找树&#xff0c;红黑树是五种不同的数据结构&#xff0c;它们有各自的特点和用途。ArrayList&#xff0c;LinkedList&#xff0c;HashTable&#xff0c;LinkedHashMap&#xff0c;HashMap 是 Java…

Camera组件

Clear Flags&#xff1a; Skybox&#xff1a;天空盒 Solid Color&#xff1a;填充颜色&#xff0c;当有空白处时填充背景颜色 Depth Only&#xff1a;只渲染想要渲染的层级 Dont Clear&#xff1a;不清除上一帧所留下来的数据&#xff0c;可以做类似残影的效果 Culling Mas…

Unity Addressable

Unity重要目录 工程中的几个重要目录 Assets存放资源、代码、配置Library大部分的资源导入到Assets目录之后&#xff0c;会转化成Unity认可的文件&#xff0c;转化后的文件会存储在这个目录Logs日志文件Packages第三方插件ProjectSettings存放各种项目设定UserSettings用户偏好…

CentOS 8 错误: Error setting up base repository

配置ip、掩码、网关、DNS VMware网关可通过如下查看 打开网络连接 配置镜像的地址 vault.centos.org/8.5.2111/BaseOS/x86_64/os/

java 阿里云 发送短信功能实现

1. 注册短信平台(以阿里云为例) 常用短信服务平台&#xff1a;阿里云、华为云、腾讯云、京东、梦网、乐信等 2. 注册成功后&#xff0c;开通短信服务 3. 设置短信签名、短信模板、AccessKey AccessKey 是访问阿里云 API 的密钥&#xff0c;具有账户的完全权限&#xff0c;我们…

C语言实现三子棋游戏

test.c源文件 - 三子棋游戏测试 game.h头文件 - 三子棋游戏函数的声明 game.c源文件 - 三子棋游戏函数的实现 主函数源文件&#xff1a; #define _CRT_SECURE_NO_WARNINGS 1#include"game.h" //自己定义的用"" void menu() {printf("*************…

代码随想录算法训练营day43

文章目录 Day43 最后一块石头的重量II题目思路代码 目标和题目思路代码 一和零题目思路代码 Day43 最后一块石头的重量II 1049. 最后一块石头的重量 II - 力扣&#xff08;LeetCode&#xff09; 题目 有一堆石头&#xff0c;每块石头的重量都是正整数。 每一回合&#xff0…

2023-07-30 LeetCode每日一题(环形链表 II)

2023-07-30每日一题 一、题目编号 142. 环形链表 II二、题目链接 点击跳转到题目位置 三、题目描述 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 n…

【探索C++中的顺序表】手动实现vector容器

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a;初阶数据结构 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对…

Fourier变换及其应用(Brad G. Osgood)——第2章——Fourier变换

第2章 Fourier变换 2.1 初识Fourier变换(A First Look at the Fourier Transform) 我们即将从Fourier级数过渡到Fourier变换。“过渡(transition)”是合适的词&#xff0c;因为我们选择了Fourier变换从周期函数到非周期函数的引出路径。 为了完成这一旅程&#xff0c;我们将把…