哈希表应用——位图

news2024/11/24 13:28:49

应用场景:海量数据处理(这里的海量是指一般数据量非常大如以亿为单位的数据量)


目录

面试题

位图概念

位图的实现

位图的应用

应用一

应用二

位图应用变形


面试题

给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在 这40亿个数中?

解决方法:

  • 遍历,时间复杂度O(N)

使用set/uordered_set遍历40亿个数字,但是40亿个数字加载到内存中代价太大(需要占用4个G左右的内存大小),不现实

  • 排序(O(NlogN)),利用二分查找(O(logN))

排序无法加载到内存中进行排序(代价太大,需要一次性开4G大小的空间),那就必须使用外排序在磁盘上排序,但是外排序的效率很低,不符合快速的特点,不能很好支持快速随机访问

  • 位图

数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一 个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在,如下图:

位图概念

所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用 来判断某个数据存不存在的。

位图的实现

#pragma once 
#include <vector>

/*
 * 位图本质上是由于需要处理海量的数据,将数据映射到比特位上来处理,大大缩小了空间的消耗
 */

namespace mystl
{
  //使用非类型模板参数接收数据量
  template<size_t N>
  class bitset
  {
  public:
    bitset()
    {
      _bit.resize(N/8+1, 0);//确保每一个位置都有对应的比特位需要+1
    }

    //将需要查找的数据映射到位置,即将对应位置设为1
    void set(size_t x)
    {
      size_t i = x / 8;//确定在第几个字节的位置
      size_t j = x % 8;//确定在第i个字节中的第几个比特位

      _bit[i] |= (1 << j);
    }

    //将数据删除,即将对应的位置设为0
    void reset(size_t x)
    {
      size_t i = x / 8;
      size_t j = x % 8;

      _bit[i] &= (~(1<<j));//将对应位置设为0,其他位置设为1,按位与后就能够不影响其他位置
    }

    //查找一个数据是否存在
    bool test(size_t x)
    {
      size_t i = x / 8;
      size_t j = x % 8;

      return _bit[i] & (1<<j);
    }

  private:
    std::vector<char> _bit;//可以使用char/int来分割比特位
  };
}

主要难度在于将得到的数据转化成对应在比特位的位置上,根据vector中存储的数据来算数据对应在比特位上的位置

位图的应用

应用一

给定100亿个整数,没排过序,设计算法找到只出现一次的整数?

上个问题就像是K模型,而这个问题就像是KV模型,分析题目知道数据的最大值为INT_MAX,而题目也只是要找只出现一次的整数,那我们统计状态只需要统计出现0次,1次,以及>=2次三种状态,而统计三种状态只需要两个比特位即可,由此可以使用两个bitset来实现封装two_bitset,分别表示00,01,10三种状态即可,一个bitset对象存储第一个比特位状态,一个bitset对象存储第二个比特位状态,实现如下:

#pragma once
template<size_t N>
  class two_bitset
  {
    public:
      //set封装bitset来表示00,01,10
      void set(size_t x)
      {
        int n1 = _bit1.test(x);
        int n2 = _bit2.test(x);

        //00是为出现,01是出现一次,10是出现>=2次
        if(n1 == 0 && n2 == 0)
          _bit2.set(x);
        else if(n1 == 0 && n2 == 1)
        {
          _bit1.set(x);
          _bit2.reset(x);
        }
      }

      //01才是只出现一次
      bool is_once(size_t x)
      {
        return !_bit1.test(x) && _bit2.test(x);
      }

    private:
      bitset<N> _bit1;//表示第一个比特位
      bitset<N> _bit2;//表示第二个比特位
  };

应用二

给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?

本质上是使用两个位图来存储每个数据的状态,位图一存储文件一中100亿个整数的状态,位图二存储文件二中100亿个整数的状态,两个文件中的数据最大值是INT_MAX,一个文件中状态的存储需要消耗512MB左右,两个文件正好占用1G内存左右,对比两个位图每一位的状态,即可得到两个文件的交集,代码如下:

#include <iostream>
#include <bitset>
using namespace std;

int main()
{
    bitset<-1> bs1;
    bitset<-1> bs2;
    //举例读取十个数据
    for(int i = 0; i < 10; ++i)
    {
        int input1 = 0;
        int input2 = 0;
        bs1.set(input1);
        bs2.set(input2);
    }
    //找到交集并输出
    for(int i = 0; i <= INT_MAX; ++i)
        if(bs1.test(i) && bs2.test(i))
            cout << i << endl;
    return 0;
}

位图应用变形

1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数

和找只出现一次的所有整数思路一致,00表示没有出现过,01表示出现过一次,10表示出现过两次,11表示出现过的次数>=3次,正好两个比特位只能表示最多四种状态,只需要统计00,01,10的情况即可,实现如下:

#pragma once
template<size_t N>
  class two_bitset
  {
    public:
      //set封装bitset来表示00,01,10,11
      void set(size_t x)
      {
        int n1 = _bit1.test(x);
        int n2 = _bit2.test(x);

        //00是为出现,01是出现一次,10是出现>=2次
        if(n1 == 0 && n2 == 0)
          _bit2.set(x);
        else if(n1 == 0 && n2 == 1)
        {
          _bit1.set(x);
          _bit2.reset(x);
        }
        else if(n1 == 1 && n2 == 0)
            _bit2.set(x);
      }

      //统计00,01,10即不超过两次
      bool Not_more_than_twice(size_t x)
      {
        //除了11以外都是不超过两次,因为两个比特位只能表示四种状态
        if(_bit1.test(x) == 1 && _bit2.test(x) == 1)
            return false;
        return ture;
      }

    private:
      bitset<N> _bit1;//表示第一个比特位
      bitset<N> _bit2;//表示第二个比特位
  };

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

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

相关文章

Java之多线程进阶

目录 一.上节内容复习 1.线程池的实现 2.自定义一个线程池,构造方法的参数及含义 3.线程池的工作原理 4.拒绝策略 5.为什么不推荐系统提供的线程池 二.常见的锁策略 1.乐观锁和悲观锁 2.轻量级锁和重量级锁 3.读写锁和普通互斥锁 4.自旋锁和挂起等待锁 5.可重入锁和…

精彩回顾 | Fortinet Accelerate 2023·中国区巡展厦门站

Fortinet Accelerate 2023中国区 5月16日&#xff0c;Fortinet Accelerate 2023中国区巡展来到魅力“鹭岛”——厦门&#xff0c;技术、产品和业务专家&#xff0c;携手亚马逊云科技、唯一网络等云、网、安合作伙伴&#xff0c;与交通、物流、金融等各行业典型代表客户&#x…

GPT大语言模型Vicuna本地化部署实践(效果秒杀Alpaca) | 京东云技术团队

​ 背景 上一篇文章《[GPT大语言模型Alpaca-lora本地化部署实践]》介绍了斯坦福大学的Alpaca-lora模型的本地化部署&#xff0c;并验证了实际的推理效果。 总体感觉其实并不是特别理想&#xff0c;原始Alpaca-lora模型对中文支持并不好&#xff0c;用52k的中文指令集对模型进…

信息安全工程实验——口令攻击和钓鱼攻击(自用)

目录 实验目的 实验原理 实验内容 练习1windows口令破解 1、基本操作 2、思考与总结 练习2&#xff1a;QQ 邮箱的钓鱼攻击 1、构造钓鱼页面 2、接收钓鱼所得的账号和密码&#xff08;分档&#xff09; 3、实验验证 4、思考与总结 实验目的 &#xff08;1&#xff09…

网络安全实验——信息收集与主机发现

目录 实验目的 实验原理 实验内容 1.信息搜集 1.ping探测 2. Nmap扫描 3. 探测总结 2.主机发现程序开发 3.主机发现 实验总结 实验目的 1.了解信息搜集的一般步骤。 2.学会熟练使用ping命令。 3.学会利用Nmap等工具进行信息搜集。 4.了解IP助手函数。 5.掌握Sen…

Python学习29:存款买房(B)

描述‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬ 你刚刚大学毕业&#xff0c;…

李莫愁给张无忌朋友圈点赞?详解SpringBoot事件机制

Spring Boot的事件机制是基于Spring框架的事件机制实现的。Spring Boot中的事件机制可以让我们在应用程序中监听和响应特定的事件&#xff0c;例如应用程序启动、关闭、上下文刷新等。 接下来&#xff0c;我们通过一个案例&#xff0c;来讲解具体怎么使用。 这个案例就是李莫…

一文看懂增值税发票识别OCR:从技术原理到 API Java 示例代码接入

引言 增值税发票识别OCR API是一项重要的技术创新&#xff0c;它在如今信息化的商业环境中发挥着重要作用。通过利用该API&#xff0c;企业和机构能够实现增值税发票的自动化识别和信息提取&#xff0c;从而在财务管理、票据核对、报销流程等方面带来许多好处。 本文将详细介…

Istio virtual service 超时和重试

在使用xshell去远程连接服务器的时候没有反应&#xff0c;这样可能等了几分钟&#xff0c;这样按下crtlc终止就行了。 有些时候微服务是多个服务组成的&#xff0c;a服务会去调用b服务&#xff0c;可能因为网络问题或者连接问题&#xff0c;没有连接成功&#xff0c;那么会尝试…

怎么把音频的声音调大?

怎么把音频的声音调大&#xff1f;我们平时会经常使用到音频文件&#xff0c;但声音大小不一&#xff0c;可能会让我们感到不适应。如果太大&#xff0c;甚至会使人吓一跳&#xff1b;如果太小&#xff0c;则难以听清楚。为了轻松聆听音频&#xff0c;我们需要将声音调整到合适…

ConvNeXt网络详解,最新ConvNeXt结合YOLO,催生YOLOv5目标检测巨变

目录 引言一、ConvNeXt的介绍1、目标检测的重要性2、YOLOv5的介绍3、ConvNeXt原理和特点4、ConvNeXt结构 二、相关研究综述1、目标检测的基础原理和流程2、YOLOv5的特点与局限性3、ConvNeXt技术在目标检测中的应用现状 三、ConvNeXt在YOLOv5中的应用与改进1、安装PyTorch和torc…

什么是栈,为什么函数式编程语言都离不开栈?

文章目录 一、什么是栈&#xff0c;什么是FILO二、栈的作用是什么&#xff0c;为什么编程语言函数调用都选择用栈&#xff1f;三、使用C模拟实现解析栈1.结构体的定义2.栈的创建及销毁3.实现入栈操作4.获取栈顶元素及出栈操作5.获取栈中有效元素个数 源代码分享 一、什么是栈&a…

临时被拉去已经在进行中的项目组「救火」,该怎么开展管理?

当你被临时拉去参与正在进行中的项目组&#xff0c;需要进行所谓的「救火」工作时&#xff0c;你需要注意的是如何开展管理&#xff0c;以确保项目能够成功完成。 首先&#xff0c;你需要了解项目的当前状态。了解项目的进展情况、目标和计划&#xff0c;以及团队成员的角色和…

Vmware Linux磁盘空间扩容

Linux磁盘空间扩容 VMware虚拟机中配置&#xff08;1&#xff09;进入虚拟机设置界面&#xff0c;选择扩展磁盘容量。&#xff08;2&#xff09; 本次是在原来30G的基础上扩展为50G。 Linux中设置&#xff08;1&#xff09; 可以看出sda3是根分区&#xff0c;下面按照博客提示&…

栈的实现(附含经典例题)

&#x1f349;博客主页&#xff1a;阿博历练记 &#x1f4d6;文章专栏&#xff1a;数据结构与算法 &#x1f68d;代码仓库&#xff1a;阿博编程日记 &#x1f365;欢迎关注&#xff1a;欢迎友友们点赞收藏关注哦&#x1f339; 文章目录 &#x1f340;前言&#x1f3c4;‍♂️数…

Redis系列--哨兵模式

一、什么是哨兵 Redis Sentinel&#xff08;哨兵&#xff09;是一个分布式系统,你可以在一个架构中运行多个哨兵(sentinel) 进程, 这些进程使用 gossip协议(基于流行病传播方式的节点或者进程之间信息交换的协议&#xff0c;在分布式系统中被广泛使用) 来接收关于Master是否下线…

MySQL5.0完全卸载教程

一、停止MySQL服务 在系统服务中找到mysql服务并停止即可。 二、卸载mysql应用程序 在控制面板中卸载mysql应用程序 三、删除mysql文件夹 找到mysql一开始安装路径的文件夹&#xff0c;然后删除掉该整个文件夹。 四、删除注册表 &#xff08;1&#xff09;按winR键&#xff0c;…

架构师日记-从代码到设计的性能优化指南 | 京东云技术团队

一 前言 服务性能是指服务在特定条件下的响应速度、吞吐量和资源利用率等方面的表现。据统计&#xff0c;性能优化方面的精力投入&#xff0c;通常占软件开发周期的10%到25%左右&#xff0c;当然这和应用的性质和规模有关。性能对提高用户体验&#xff0c;保证系统可靠性&…

Java经典笔试题—day10

Java经典笔试题—day10 &#x1f50e;选择题&#x1f50e;编程题&#x1f95d;井字棋&#x1f95d;密码强度等级 &#x1f50e;结尾 &#x1f50e;选择题 (1)下列运算符合法的是&#xff08; &#xff09; A.&& B.<> C.if D.: A B. 泛型的标志, 例如 <T>…

【iOS】—— AFNetworking源码学习

AFNetworking 文章目录 AFNetworkingAFHTTPSessionManager *sessionManager [AFHTTPSessionManager manager];请求过程1、调用请求序列化类中的requestWithMethod方法进行序列化处理2、调用dataTaskWithRequest来生成一个datatask任务 AFURLSessionMangerAFHTTPSessionManagerU…