数据结构学习之路-集合

news2025/5/11 16:35:54

集合Set

  • 集合的特点
  • 集合的内部实现(使用链表)
  • 集合的内部实现(使用红黑树)
  • 复杂度分析
  • 使用红黑树实现集合的限制

集合的特点

  • 不存放重复的元素
  • 常用于去重
    例如:存放新增的IP地址,统计新增IP量;存放词汇,统计词汇量。。。

集合不允许有重复的元素存在,因子当新添加的元素已经存在集合中,就会去重。集合的特点就是保证,元素的唯一性。

集合的内部实现(使用链表)

集合的内部接口,大概如下:
在这里插入图片描述
集合其实也可以用线性表实现,最最不同的特点,就是集合不允许重复元素。所以,我们在设计集合时,只需要注重这一点即可。

可以实现集合的数据结构有很多,比如:动态数组,链表,红黑树。。。

我们先用链表来实现集合。

  • 首先,定义一下集合的接口:
public interface Set<Type> {
    int size();
    boolean isEmpty();
    void clear();
    boolean contains(Type element);
    void add(Type element);
    void remove(Type element);
    void traversal(Visitor<Type> visitor);

    public static abstract class Visitor<Type>{
        boolean stop;
        public abstract boolean visit(Type element);
    }
}
  • 然后定义一个ListSet类,实现这些接口:内部使用链表实现。需要注意的就只是添加元素的时候,保证不重复添加即可。
public class ListSet<Type> implements Set<Type> {
    //使用链表来实现集合,这里定义一个链表
    private List<Type> list = new LinkedList<>();

    @Override
    public int size() {
        return list.size();
    }

    @Override
    public boolean isEmpty() {
        return list.isEmpty();
    }

    @Override
    public void clear() {
        list.clear();
    }

    @Override
    public boolean contains(Type element) {
        return list.contains(element);
    }

    @Override
    public void add(Type element) {
        //添加就不能直接调用list的添加了,需要引入集合特色\

        //第一种做法:如果存在,那就不添加当前
        if(list.contains(element)) return;
        list.append(element);

        //第一种做法:如果存在,那就覆盖掉原来的
        int index = list.indexOf(element);
        if(index != -1){
            //说明原本集合里就有element,那就覆盖
            list.set(index,element);
        }else {
            //不存在,那就添加
            list.append(element);
        }

    }

    @Override
    public void remove(Type element) {
        //删除的话,首先判断存不存在,如果集合中确实有元素element再执行删除操作
        if(list.indexOf(element) != -1){
            list.remove(list.indexOf(element));
        }
    }

    @Override
    public void traversal(Visitor<Type> visitor) {
        //因为是链表,因此内部可以用for循环实现集合的遍历,取出集合中每一个元素交给visitor去使用
        if(visitor == null) return;
        int size = list.size();
        for (int i = 0; i < size; i++) {
            visitor.visit(list.get(i));
        }
    }
}

OK,我们来测试一下:

public static void main(String[] args) {
    Set<Integer> ListSet = new ListSet<>();

    ListSet.add(10);
    ListSet.add(11);
    ListSet.add(11);
    ListSet.add(12);

    ListSet.traversal(new Set.Visitor<Integer>() {
        @Override
        public boolean visit(Integer element) {
            System.out.println(element);
            return false;
        }
    });
}

可以看到,元素并没有被重复添加,集合的性质也得到了实现。

在这里插入图片描述

集合的内部实现(使用红黑树)

用红黑树来实现集合,也就意味着,我们集合中的所有元素,本质上是在红黑树上。

因为红黑树在添加节点的时候,会不断地比较大小,然后判断添加到左子树还是右子树。一旦发现,添加的节点元素等于某个节点元素值,就会覆盖。因此红黑树内部就实现了去重的功能。因此,集合在实现add方法时,直接调用红黑树的add方法就行了,不用做任何额外操作。

public class TreeSet<Type> implements Set<Type> {
    private RBTree<Type> tree = new RBTree<>();

    @Override
    public int size() {
        return tree.size();
    }

    @Override
    public boolean isEmpty() {
        return tree.isEmpty();
    }

    @Override
    public void clear() {
        tree.clear();
    }

    @Override
    public boolean contains(Type element) {
        return tree.contains(element);
    }

    @Override
    public void add(Type element) {
        //红黑树有一个特点就是,比较,然后添加元素。如果发现相同,就会覆盖点原节点的值
        //也就是说,红黑树默认是去重的,因此对于集合的添加,不需要额外操作
        tree.add(element);
    }

    @Override
    public void remove(Type element) {
        tree.remove(element);
    }

    @Override
    public void traversal(Visitor<Type> visitor) {
        //使用tree的中序遍历即可
        tree.InorderTraversal();
    }
}

复杂度分析

复杂度对比:红黑树实现 vs 链表实现

对于红黑树实现来说,增加删除搜索,集合直接调用红黑树的接口,因此复杂度都是logn级别的。

对于链表实现来说,增加删除搜索,集合也是直接调用链表的接口,因此搜索来说,是O(n)级别的;添加节点的时候,需要搜索然后再添加,也是O(n)级别的;删除节点,也是O(n)级别的;

因此,从复杂度来说,红黑树实现是优于链表的。

我们做一个实际测试:对256018个单词进行add,contains,remove。用链表实现的set耗时7.089秒,用红黑树实现的set耗时0.169秒。这是多么大的差距啊!因此,红黑树真的很强。

在这里插入图片描述

使用红黑树实现集合的限制

使用红黑树实现集合的一个最大限制就是:添加进集合的元素,必须具备可比较性!

如果将来我添加进去的元素不具备可比较性,那就不能使用红黑树来实现set了,也就是不能使用TreeSet了。

如果将来,我真的有一堆没有可比较性的数据,还想获得TreeSet一样的性能,怎么办呢?

那就要使用:哈希表!!!后续会介绍

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

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

相关文章

torch中的model.eval()、model.train()详解

&#x1f468;‍&#x1f4bb;个人简介&#xff1a; 深度学习图像领域工作者 &#x1f389;工作总结链接&#xff1a;https://blog.csdn.net/qq_28949847/article/details/128552785 链接中主要是个人工作的总结&#xff0c;每个链接都是一些常用demo&#xff0c…

Laravel框架05:模型和自动验证

Laravel框架05&#xff1a;模型和自动验证 一、模型&#xff08;AR模式&#xff09;概述二、定义模型三、调用模型四、基本操作1. 添加数据① AR模式② Request 2. 查询数据3. 修改操作① AR模式② update 4. 删除操作 五、控制器验证1. 基本语法2. 输出错误信息 一、模型&…

今麦郎跻身“我最喜欢中国品牌”榜,致力领航中国品牌发展新范式

在中国经济探寻高质量发展的当下&#xff0c;中国民营企业肩负着推动经济发展的重任。在当前中国经济向上向前的大背景下&#xff0c;展示中国特色、传播中国文化、践行社会责任多位一体的高质量品牌越来越受到重视。但冰冻三尺非一日之功&#xff0c;唯有经历时间考验&#xf…

Spring:Spring 整合 MyBatis 的具体过程

文章目录 Spring&#xff1a;Day 04整合 MyBatis一、配置环境1. 导入依赖2. 准备一个数据库 二、用 Spring 整合 MyBatis1. 编写通用配置文件2. 编写实现类3. 编写 Spring 配置文件4. 测试5. 分析总结 三、拓展1. 实现2. 总结 四、事务1. 概述2. 没有事务时3. 声明式事务4. 总结…

“Shell“SNAT,DNAT

文章目录 一.SNAT1.1 SNAT原理1.2 SNAT的应用环境1.3 SNAT工作原理1.4 进行SNAT转换后1.5 配置SNAT策略1.6SNAT实验 二.DNAT2.1 DNAT工作原理2.2 配置DNAT策略2.3 DNAT实验 一.SNAT 1.1 SNAT原理 SNAT原理&#xff1a;修改数据包的源地址。SNAT 应用环境&#xff1a;局域网主…

基础学习——关于卷积层的记录

文章目录 前言一、功能层1、池化层2、nn.BatchNorm2d()3、全连接层4、softmax层 二、卷积层1、普通卷积2、空洞卷积3、多尺度卷积4、分组卷积5、深度可分离卷积6、形变卷积 前言 老是忘有些模块的具体作用&#xff0c;记录一下。 一、功能层 1、池化层 池化层夹在连续的卷积…

总结最全面的TCP、UDP、Socket、HTTP网络编程面试题

先看一天面试的经验&#xff1a; 第一场&#xff1a; 面试官&#xff1a;你说一下TCP的三次握手 我&#xff1a;第一次Client将SYN置1......、第二次Server收........、 第三次........ 面试官&#xff1a;很难背吧&#xff1f; 我&#xff1a;......是啊&#xff0c;很难&…

harbor安装

文章目录 先决条件硬件软件网络端口 安装docker签发证书生成证书颁发机构证书 生成服务器证书向 Harbor 和 Docker 提供证书 下载harbor安装包containerd 配置私有仓库&#xff08;二选一&#xff09;分发证书(如上文只是路径变了)配置登录加密登录打标签并推送与拉取 docker 配…

【EasyPoi实战系列】Spring Boot使用EasyPoi动态控制导出的列 - 第471篇

历史文章&#xff08;文章累计460&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 用…

机器学习神经网络——GBDT(Gradient Boosting Decision Tree 梯度提升决策树)算法

系列文章目录 机器学习神经网络——Adaboost分离器算法 机器学习之SVM分类器介绍——核函数、SVM分类器的使用 机器学习的一些常见算法介绍【线性回归&#xff0c;岭回归&#xff0c;套索回归&#xff0c;弹性网络】 文章目录 系列文章目录 前言 一、GBDT(Gradient Boos…

计算机网络:物理层

物理层 1. 通信基础1.1 基本概念1.1.1 通信模型1.1.2 通信方式1.1.3 数据传输方式1.1.4 数据同步的传输/通信方式1.1.5 码元1.1.6 速率1.1.7 带宽 1.2 奈氏准则|香农定理1.2.1 奈氏准则1.2.2 香农定理 1.3 编码、调制1.3.1 数字数据编码为数字信号1.3.2 数字数据调制为模拟信号…

Google Colab的使用方法

什么是 Google Colab&#xff1f; Colaboratory是一个 Google 研究项目&#xff0c;旨在帮助传播机器学习培训和研究成果。是一个Jupyter 笔记本环境&#xff0c;不需要进行任何设置就可以使用&#xff0c;并且完全在云端运行。Colaboratory笔记本存储在 Google 云端硬盘中&…

“超级品牌”已成型!解码名创优品的进阶之路

随着经济复苏&#xff0c;消费者心智和市场趋势逐渐发生变化&#xff0c;零售市场竞争步入深水区&#xff0c;为品牌带来了更大考验。但反过来&#xff0c;也令更多潜力股加速崛起。 北京时间5月16日&#xff0c;名创优品集团&#xff08;NYSE:MNSO;HKEX: 9896&#xff09;公布…

ResourceManager启动报错:Queue configuration missing child queue names for root【已解决】

Queue configuration missing child queue names for root 现象报错分析ResourceManager输出日志解决 现象 start-all.sh后缺少RM的进程 报错 查看启动日志输出文件 2023-05-23 19:28:19,863 INFO [main] resourcemanager.RMNMInfo (RMNMInfo.java:<init>(63)) - Re…

【Linux】进程控制 — 进程终止 + 进程等待

文章目录 &#x1f4d6; 前言1. 再次理解fork()函数1.1 fork()之后子进程代码和数据问题&#xff1a;1.2 fork()之后操作系统做了什么&#xff1a;1.3 为什么要写时拷贝&#xff1f;&#xff1f; 2. 进程终止2.1 main函数的返回值&#xff1a;2.2 exit() 和 _exit()&#xff1a…

以京东首页为例,设计用例框架。

以下是一个可能的京东首页的用例框架设计&#xff1a; 1. 区域划分&#xff1a; a. 顶部导航栏&#xff1a;包括京东的Logo、搜索框、登录/注册入口、购物车等。 b. 主要内容区域&#xff1a;展示各类商品、促销活动、广告位等。 c. 商品分类导航&#xff1a;提供各类…

复习之Linux下的文件管理

1.文件的建立 #touch westos-------建立空文件/修改文件的建立时间 &#xff08;1&#xff09;建立空文件 &#xff08;2&#xff09;修改文件的建立时间 ----右击点属性显示文件的建立时间 ---- 再次输入touch westos,westos文件的建立时间更新&#xff01; -----westos -t…

使用 Kafka Assistant,为您的开发加速

简要介绍 快速查看所有 Kafka 集群&#xff0c;包括Brokers、Topics和Consumers支持各种认证模式&#xff1a;PLAINTEXT、SASL_PLAINTEXT、SSL、SASL_SSL对Kafka集群进行健康检查查看分区中的消息内容并添加新消息查看消费者订阅了哪些主题&#xff0c;以及分区被分配给了哪些…

金融、医疗、教育等各场景下小程序SDK的应用

近年来&#xff0c;随着数字经济的飞速发展和移动终端的迅速普及&#xff0c;移动互联网全面覆盖&#xff0c;各类应用服务层出不穷&#xff0c;涵盖了方方面面的生活、工作和学习。 而小程序作为一种轻量级的应用形态&#xff0c;越来越受到开发者和用户的欢迎。为了满足不同行…

DataNode启动报错Failed to add storage directory [DISK]file:【已解决】

Failed to add storage directory [DISK]file hadoop启动后缺少DataNode进程报错out文件报错log文件解决 hadoop启动后缺少DataNode进程 jps查看hadoop进程缺少DataNode的进程 报错out文件 查看DataNode的out日志 DataNode启动报错 ulimit -a for user root core file size…