set,map(java)

news2025/1/12 4:50:30

前言:要了解set和map,首先需要对搜索树和哈希有一定的了解,才能进一步深入的了解set和map。

1.搜索树

(1)性质:

若它的左子树不为空,则左子树上所有节点值都小于根节点的值。

若它的右子树不为空,则右子树上所有节点值都大于根节点的值。

它的左右子树也分别为二叉搜索树。

二叉搜索树中不允许出现相同的值

eg:

(2)相关功能的实现:

前提得实现一个节点类TreeNode,包含left(左子树),right(右子树),val三个属性。

a.查找:

分析:

时间复杂度:

最好情况:O(\log_{2}N)

最坏情况:O(N) 

代码实现:

public TreeNode search(int val) {
    if(root == null) {
        return null;
    }
    TreeNode cur = root;
    while(cur != null) {
        if (cur.val > val) {
            //进到左边
            cur = cur.left;
        } else if (cur.val < val) {
            //进到右边
            cur = cur.right;
        } else {
            return cur;
        }
    }
    return null;
}

b.插入:

分析:

时间复杂度与查找的相同。

代码实现:

public void insert(int val) {
    if(root == null) {
        root = new TreeNode(val);
        return;
    }
    TreeNode node = new TreeNode(val);
    TreeNode cur = root;
    TreeNode parent = null;
    while(cur != null) {
        parent = cur;
        if (cur.val > node.val) {
            //进到左边
            cur = cur.left;
        } else if (cur.val < node.val) {
            //进到右边
            cur = cur.right;
        } else {
            return;
        }
    }
    //记录父亲节点的用处
    if(parent.val > node.val) {
        parent.left = node;
    }
    if(parent.val < node.val) {
        parent.right = node;
    }
}

c.删除:

分析:

时间复杂度与查找和插入相同。

代码实现:

public void delete(int val) {
    if(root == null) {
        return;
    }
    TreeNode cur = root;
    TreeNode parent = null;
    while(cur != null) {
        cur = parent;
        if (cur.val > val) {
            //进到左边
            cur = cur.left;
        } else if (cur.val < val) {
            //进到右边
            cur = cur.right;
        } else {
            removeNode(parent,cur);
        }
    }
}
private void removeNode(TreeNode parent, TreeNode cur) {
    if(cur.left == null) {
        if(cur == root) {
            cur = cur.right;
        }else if(parent.right == cur) {
            parent.right = cur.right;
        }else if(parent.left == cur) {
            parent.left = cur.right;
        }
    }else if(cur.right == null) {
        if(cur == root) {
            cur = cur.left;
        }else if(parent.right == cur) {
            parent.right = cur.left;
        }else if(parent.left == cur) {
            parent.left = cur.left;
        }
    }else {
        TreeNode tmpParent = cur;
        TreeNode tmp = cur.right;
        while(tmp.left != null) {
            tmpParent = tmp;
            tmp = tmp.left;
        }
        cur.val = tmp.val;
        if(tmpParent.left == tmp) {
            tmpParent.left = tmp.right;
        }
        if(tmpParent.right == tmp) {
            tmpParent.right = tmp.right;
        }
    }
}

(3)和集合类的关系:

TreeSet和TreeMap即java中运用二叉搜索树实现的Set和Map;但实际上是一颗红黑树,红黑树是一颗近似平衡的二叉搜索树(不会出现一些单只树的情况)。

2.哈希表

(1)概念:

通过构造一种存储结构,和某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一 一映射的关系,从而在查找时候能很快速的查找到对应的元素。构造出来的存储结构就成为哈希表,某种转换函数称为哈希函数,上述这中查找方式称为哈希(散列)方法。

eg:

(2)冲突:

a.概念:

不同关键字通过哈希函数计算出相同的哈希地址。

b.避免:

冲突是不能够完全避免的,我们只能设计一个比较合理的哈希函数来尽量降低哈希冲突率

直接定制法:Hash(key) = A * key + B 使用场景:适合查找比较小且连续的情况。

除留余数法:Hash(key) = key % p(p <= m,m为哈希表的长度)

c.负载因子调节(\alpha):

\alpha = 填入表中的元素/哈希表的长度,\alpha越大,表明冲突的概率越大,反之则越小。

d.解决方式:

闭散列:

有线性探测和二次探测两种方式:

线性探测:

线性探测有个缺陷就是冲突的元素易容易堆积在一起。 

二次探测:

研究表明:当表的长度为质数并且负载因子不超过0.5时,新的表项一定能插入,而且任何一个位置都不会被探查两次。因此只要表中有一半的位置,就不存在表满的问题。此时在搜索时可以不考虑装满的情况,但在插入时必须确保表的负载因子不超过0.5,否则需要扩容。

因此闭散列最大的缺陷就是表的利用率比较低。

开散列:(哈希桶,开链法,链地址法)

各个桶中的元素通过一个单链表串起来,各链表头节点存储在哈希表中。

eg:

从上图我们可以看出每个哈希桶中放的都是冲突的元素,此时就可以将开散列认为时是把一个大集合中的搜索问题转化为在小集合中做搜索了。

 3.Map和Set

Set和Map都是java中专门用来搜索的容器/数据结构,其搜索的效率与具体的实列类有关。

以前的搜索方式:直接遍历,二分查找......,这些更适合于静态查找。

而Set和Map更适合于动态查找。

搜索的数据:关键字(key)和关键字对应的称为值(value),它们一起称为key-value键值对。一般有两种模型:纯key模型(Set)和纯key-value模型(Map)。

(1)TreeMap,HashMap:

map是一个接口没有继承于Collection接口,存储的是key-value键值对,key是唯一的,不能重复。

a.使用:

 关于Map.Entry<K,V>的说明:

Entry也是一个接口,只不过是Map内部实现的接口,它是用来存放key-value键值对的映射关系。

主要有三个使用方法:

 Map.Entry<K,V>中没有提供设置key的方法。

b.HashMap源码相关解析:

c.比较:

d.注意:

Map是一个接口,不能够进行实列化对象,要new对象只能通过TreeMap或者HashMap来实现。

Map中key,value的类型可以是所有类型,但TreeMap中的key不能为nul,而HashMap可以

Map中key是唯一的,value不是唯一的。

Map中的key是不能直接进行修改的,Map.Entry中只提供了setValue方法,并为提供setKey方法,所以要想进行修改key,只能删除这个键值对,重新放入元素。

(2)TreeSet,HashSet:

Set是一个接口,继承与Collection接口,Set集合类可以达到天然去重的效果。

a.使用:

b.比较:

c.注意:

Set是一个接口,不能直接实例化对象,只能通过TreeSet或HashSet来new对象。

Set中的元素是唯一的,所以有天然去重的效果。

TreeSet中的值不能为null,HashSet可以。

Set的底层就是有Map来实现的,其使用key与Object一个默认对象作为键值对插入到Map中的。

Set中的key也是不能修改的,要修改只能删除,重新放入。

Set常见实列化的类有TreeSet和HashSet,此外还有LinkedHashSet,其是在HashSet的基础上维护了一个双向链表来记录元素的插入次序。

4.OJ题:

(1)随机链表的复制

分析:

代码实现:

class Solution {
    public Node copyRandomList(Node head) {
        HashMap<Node,Node> map = new HashMap<>();
        Node cur = head;
        while(cur != null) {
            Node node = new Node(cur.val);
            map.put(cur,node);
            cur = cur.next;
        }
        cur = head;
        while(cur != null) {
            map.get(cur).next = map.get(cur.next);
            map.get(cur).random = map.get(cur.random);
            cur = cur.next;
        }
        return map.get(head);
    }
}

 (2)旧键盘

分析:

代码实现:

public static void func(String str1, String str2) {
    Set<Character> set = new HashSet<>();
    for (char ch : str2.toUpperCase().toCharArray()) {
        set.add(ch);
    }

    Set<Character> set1 = new HashSet<>();
    for (char ch : str1.toUpperCase().toCharArray()) {
        if (!set.contains(ch) && !set1.contains(ch)) {
            System.out.print(ch);
            set1.add(ch);
        }
    }
}

(3)前k个高频单词

分析:

代码实现:

class Solution {
    public List<String> topKFrequent(String[] words, int k) {
        HashMap<String, Integer> map = new HashMap<>();
        for (String word : words) {
            if (map.get(word) == null) {
                map.put(word, 1);
            } else {
                int val = map.get(word);
                map.put(word, val + 1);
            }
        }
        // 建立小根堆
        PriorityQueue<Map.Entry<String, Integer>> queue = new PriorityQueue<>(
                new Comparator<Map.Entry<String, Integer>>() {
                    @Override
                    public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                        if (o1.getValue().compareTo(o2.getValue()) == 0) {
                            return o2.getKey().compareTo(o1.getKey());
                        }
                        return o1.getValue().compareTo(o2.getValue());
                    }
                });
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            if (queue.size() < k) {
                queue.offer(entry);
            } else {
                Map.Entry<String, Integer> tmp = queue.peek();
                if (tmp.getValue().compareTo(entry.getValue()) < 0) {
                    queue.poll();
                    queue.offer(entry);
                } else {
                    // 按照字符顺序排
                    if (tmp.getValue().compareTo(entry.getValue()) == 0) {
                        if (tmp.getKey().compareTo(entry.getKey()) > 0) {
                            queue.poll();
                            queue.offer(entry);
                        }
                    }

                }
            }
        }
        List<String> list = new LinkedList<>();
        for (int i = 0; i < k; i++) {
            Map.Entry<String, Integer> tmp = queue.poll();
            list.add(tmp.getKey());
        }
        Collections.reverse(list);
        return list;
    }
}

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

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

相关文章

事件如何驱动图表运行

状态流图如何响应事件 Stateflow图表仅在以循环方式响应事件时执行。 由于图表在单个线程上运行&#xff0c;因此基于事件发生的操作对该事件是原子性的。图表中由事件引起的所有活动都在执行返回到接收事件之前发生的活动之前完成。一旦事件启动了一个操作&#xff0c;除非被…

全网最全程序员接单网站

程序员客栈-领先的程序员自由工作平台-程序员兼职 (proginn.com) 闲鱼 - 闲不住&#xff0c;上闲鱼&#xff01; (goofish.com) 猪八戒网-品质企业服务 就找猪八戒 (zbj.com) 电鸭社区-专注远程工作招聘交流-远程工作&#xff0c;从电鸭开始 (eleduck.com) 开源众包-百万开发者…

Java台球厅助教教练预约上门到店系统源码

&#x1f3b1;一杆在手&#xff0c;天下我有&#xff01;台球助教教练预约系统&#xff0c;让球技飙升不是梦&#x1f680; &#x1f3af;【开篇&#xff1a;台球爱好者的福音来啦&#xff01;】&#x1f3af; 还在为找不到合适的台球教练而烦恼吗&#xff1f;或是想要在家就…

代码实践思考:C++和Python

起因 在人工智能工具日益强大的今天 如何更高效的进行代码学习 如何借助智能工具实现代码转换&#xff1f; 是否直接可以使用&#xff1f;为何&#xff1f; 如何实现不同的编程语言之间代码的无损转换&#xff1f; x86与arm C 云课五分钟-02第一个代码复现-终端甜甜圈C-CS…

GEE错误——文件导出的时候出现Error: User memory limit exceeded. (Error code: 3)

错误简介 在试图将我的表导出到资产文件夹,但出现了内存错误。我不知道我做错了什么。相同的脚本适用于其他年份。文件导出的时候出现Error: User memory limit exceeded. (Error code: 3) 函数 reduceToVectors(reducer, geometry, scale, geometryType, eightConnected,…

雪花算法的一些问题解析

前言 最近做项目&#xff0c;有些老旧项目&#xff0c;需要生成分布式唯一ID&#xff0c;不允许重复&#xff0c;此时如果要对其他中间件和数据库依赖小&#xff0c;那么就需要一套固定的ID生成规则&#xff0c;雪花算法就正当合适&#xff0c;当时Twitter就是用来存储数据库I…

服务器主机安全有多重要

一、什么是主机安全 主机安全&#xff0c;作为维护计算机系统核心安全的基石&#xff0c;旨在全面捍卫硬件与软件免受任何未经授权的侵扰、篡改、数据泄露等安全挑战。这一过程不仅聚焦于数据存储与处理的保密性、完整性及可用性&#xff0c;还深入至硬件构造、固件层、以及系…

利用C++11的异步操作实现一个线程池

利用C11的异步操作实现一个线程池 利用C11的异步操作实现一个线程池 介绍关于一些代码细节的解释测试 介绍 基于线程池执行任务的时候&#xff0c;入口函数内部执行逻辑是固定的&#xff0c;因此选择std::packaged_task加上std::future的组合来实现。 具体使用可以见我上一…

2025年第7届图像处理和机器视觉国际会议 (IPMV 2025)即将召开!

2025年第7届图像处理和机器视觉国际会议 (IPMV 2025)将于2025年1月10日-12日在中国香港举行。图像处理和机器视觉作为当代信息技术领域的重要分支&#xff0c;不仅推动了人工智能技术的飞速发展&#xff0c;也为各行各业带来了革命性的变革。本次会议旨在汇聚全球图像处理和机器…

极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图

目录 极致的灵活度满足工程美学&#xff1a;用Vue Flow绘制一个完美流程图 一、环境要求 二、初识Vue Flow 2.1、安装Vue Flow 2.2、Vue Flow构成 2.3、一个小坑 2.4、入门案例 三、Vue Flow优秀的自定义功能 3.1、引入 3.2、节点与连线的自定义 ①打样&#xff08;…

MySQL - 通过SQL语句导出数据到CSV文件

在 MySQL 中&#xff0c;可以使用 SELECT ... INTO OUTFILE 语句将查询结果导出为 CSV 文件&#xff0c;然后再将 CSV 文件转换为 Excel 格式。以下是一个示例&#xff1a; SELECT column1, column2, column3 INTO OUTFILE /path/to/file.csv FIELDS TERMINATED BY , ENCLO…

git 迁移仓库的方法

git Git是一个开源的分布式版本控制系统&#xff0c;由Linus Torvalds在2005年创建&#xff0c;用于有效、高速地处理从小到大的项目管理。它最初是为Linux内核开发而设计的&#xff0c;但很快被广泛用于各种项目。 以下是Git的一些主要特性&#xff1a; 分布式架构&#xff…

接近传感器 - 从零开始认识各种传感器【第十七期】

1、什么是接近传感器 接近传感器常被用于检测物体的距离或者是否有物体靠近。它通常发射电磁场或电磁波&#xff08;例如红外线&#xff09;来探测物体的位置。当有物体靠近时&#xff0c;传感器会接收到反射的电磁波信号&#xff0c;从而触发相应的电路或者控制系统。它广泛应…

Helm(二)

一、Chart模板流程控制if_with_range 1.if 修改values.yaml cat > values.yaml <<EOF myname: yeunyi service: type: ClusterIP port: 80 myport: 8080 EOF 修改service.yaml cat > templates/service.yaml <<EOF apiVersion: v1 kind: Service met…

TC8:SOMEIP_ETS_007-008

SOMEIP_ETS_007: echoBitfields 目的 检查位字段是否能够被顺利地发送和接收。 测试步骤 Tester:创建SOME/IP消息Tester:使用method echoBitfields发送SOME/IP消息DUT:返回method响应消息,其中位字段的顺序与请求相比是反向的期望结果 3、DUT:返回method响应消息,其中位…

微软蓝屏”事件暴露了网络安全哪些问题?

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

探秘数字孪生技术在智慧校园的应用

在当今教育信息化的浪潮中&#xff0c;数字孪生技术逐渐成为智慧校园建设的重要助推器。这一技术通过构建真实世界的数字化映像&#xff0c;不仅提升了校园管理的效率&#xff0c;更为师生的日常学习生活提供了全新的体验。首先&#xff0c;数字孪生可以将校园内的各类设施、环…

七夕告白攻略:天使智能体教你如何设计完美表白卡片!独属程序员地浪漫!

文章目录 &#x1f495;七夕浪漫告白天使&#x1f495;&#x1f495;浪漫风格的表白卡片设计&#x1f495;&#x1f495;甜蜜风格的表白卡片设计&#x1f495;&#x1f495;温馨风格的表白卡片设计&#x1f495;&#x1f495;幽默风格的表白卡片设计&#x1f495;&#x1f495;…

使用java读取本地文件内容并输出,java读取文件内容,节省内存开销

java使用FileInputStream读取本地文件内容 java使用Stream流读取本地文件内容 1.先在自己笔记本选一个目录创建文件&#xff0c;这里就选择在D盘创建一个 word.txt文件 随意输入内容例如 2.直接来直接复制代码运行 import java.io.*; import java.nio.file.Files; import ja…

rust sip电话(基于tauri 、pjsip库)

本文尝试下rust 的tauri 桌面运用 原因在于体积小 1、pjsip 提供了rust 接口官方的 rust demo 没编译出来 在git找了个sip-phone-rs-master https://github.com/Charles-Schleich/sip-phone-rs 可以自己编译下pjsip lib库替换该项目的lib 2、创建一个tauri demo 引用 [depe…