哈希应用位图 | 位图概述与代码实现 | 关于位图的几个面试题

文章目录

        • 1.位图的概述与实现
          • 1.1.位图的引出与概述
          • 1.2.位图的代码实现
          • 1.3.位图的应用及其他面试题

1.位图的概述与实现

当然C++库中也有位图的实现:链接

1.1.位图的引出与概述

面试题:给40亿个不重复的无符号整数(0~2^32),没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中

能不能,将40亿个排序 + 二分查找,又或者整数存放在map或set,理论上是可以的只要你的内存足够大!无符号整数在32位机器下要用32个比特位来存放,我们按40个比特位算40亿个需要160亿个字节,那么1G大概是10亿个字节,存放40亿个无符号整数要16G左右的内存空间,普通配置的电脑是存放不下的!

能不能一个整数对应用一个比特位来标定

32位标定一个整数的状态是在不在,太浪费,我们可以使用1个比特位通过哈希的直接定址法来标定整数的状态。1G是80亿个比特位,那么40亿个无符号整数大概就是0.5G的内存。

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

1.2.位图的代码实现

位图的实现

在这里插入图片描述

一个位图中可以使用vector<int>来存放,40亿有很多个int,我们可以是使用 n / 32找到整数n存放第几个int位置,再通过n % 32找到存放在哪个比特位上,如果是添加,将对应的比特位通过位运算将其置成1即可,如果是删除将对应的比特位通过位运算将其置成0即可。

添加操作

将对应的比特位置成1即可

void set(int n) 
{size_t index = n / 32;size_t bit_index = n % 32;_bitset[index] |= (1 << bit_index);
}

下面假设要将下标为2的比特位置成1:

在这里插入图片描述

让1左移2位,然后或运算,或等是为了改变状态。这里不用考虑大小端的问题,1左移是向高位移动,至于大端还是小端怎么样是机器内部的事!删除和查找是类似的!

删除操作

void reset(int n) 
{size_t index = n / 32;size_t bit_index = n % 32;_bitset[index] &= (~(1 << bit_index));
}

查找操作

bool test(int n) 
{size_t index = n / 32;size_t bit_index = n % 32;return _bitset[index] & (1 << bit_index);
}

完整代码

#include<vector>
#include<iostream>
namespace xiYan
{template<size_t N>class bitset{public:bitset() {_bitset.resize(N, 0);}void set(int n) {size_t index = n / 32;size_t bit_index = n % 32;_bitset[index] |= (1 << bit_index);}bool test(int n) {size_t index = n / 32;size_t bit_index = n % 32;return _bitset[index] & (1 << bit_index);}void reset(int n) {size_t index = n / 32;size_t bit_index = n % 32;_bitset[index] &= (~(1 << bit_index));}private:std::vector<int> _bitset;};
}// 测试代码
#include"bitset.h"
using namespace std;void main() {// 32位大概是43亿个无符号整数,如果是40亿个,我们直接开辟sizt_t的最大值(-1)即可// xiYan::bitset<-1> bs;xiYan::bitset<100> bs;int arr[] = { 1,7,4,3,22,9,7 };for (auto num : arr) {bs.set(num);}cout << bs.test(7) << endl;cout << bs.test(17) << endl;;bs.reset(7);cout << bs.test(7) << endl;return 0;   
}
1.3.位图的应用及其他面试题
  1. 给定100亿个整数,设计算法找到只出现一次的整数

需要找到出现一次的整数,说明1个比特位标记在不在的状态是不行了!我们可以考虑用两个比特位来标识00 01 10 11其中01标识只出现一次。

在这里插入图片描述

用一个位图中的两个比特位来标识。

在这里插入图片描述

用两个位图对应的比特位来表示,显然是方式2好,可以直接复用位图的结构!方式1要考虑如何切分出两个比特位还需要重新写一遍代码,麻烦些。

方式2的完整代码

#pragma once
#include<vector>
#include<iostream>
#include<bitset>namespace xiYan
{template<size_t N>class towBitset{public:void set(int n){if (!_one.test(n) && !_tow.test(n)) {_one.set(n);}else if (_one.test(n) && !_tow.test(n)) {_tow.set(n);_one.set(n);}else {return;}}bool test(int n) {return (_one.test(n) && !_tow.test(n));}private:std::bitset<N> _one;std::bitset<N> _tow;};
}// 测试代码
#include"bitset.h"
using namespace std;void test2()
{xiYan::towBitset<100> bs;// 这里没考虑负数的情况int arr[] = { 1,7,7 };for (auto num : arr) {bs.set(num);}cout << bs.test(7) << endl;cout << bs.test(2) << endl;cout << bs.test(1) << endl;
}
  1. 给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集

在这里插入图片描述

100亿个整数有好多重复的数字,求交集不需要重复的,所以只需要将数据存放到两个位图中,然后对两个位图中的两个对应的位置按位与如果是0则不是交集,非0则是交集。

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

和第一个题相似,只不过,00 01 10 11 则10表示出现两次!

位图的应用

  1. 快速查找某个数据是否在一个集合中
  2. 排序 + 去重
  3. 求两个集合的交集、并集等
  4. 操作系统中磁盘块标记
  5. 操作系统中文件使用open系统调用的flage选项传入多个参数的时候也使用到了位图
int open(const char *pathname, int flags)
int fd = open("log1.txt",O_WRONLY | O_CREAT | O_TRUNC);

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode 01背包问题

典型的01背包问题可以暴力求解&#xff0c;直接将所有可能全部遍历然后挑选符合条件的即可&#xff0c;但这样时间复杂度过高&#xff0c;有2的n次方。 所以我们在这里采用动态规划的方式来做&#xff0c;并且&#xff0c;我们可以采用二维数组或者一维数组来做。 二维数组&a…

SpringBoot项目启动报java.nio.charset.MalformedInputException Input length = 1解决方案

报错详情 SpringBoot启动报错java.nio.charset.MalformedInputException: Input length 1 报错原因 出现这个的原因&#xff0c;就是解析yml文件时&#xff0c;中文字符集不是utf-8的原因&#xff0c;这是maven在项目编译时&#xff0c;默认字符集编码是GBK。 解决方式 检…

PCL 计算点云AABB包围盒的体积

目录 一、AABB包围盒二、代码实现三、结果展示四、相关链接本文由CSDN点云侠原创,原文链接。爬虫自重,把自己当个人。 一、AABB包围盒 AABB包围盒又称了 轴对齐包围盒,是点云包围盒里最简单的一种,其计算方法也极其简单。获取包围盒之后,根据包围盒的长宽高进行体积计算即…

小米14 ULTRA:重新定义手机摄影的新篇章

引言 随着科技的飞速发展&#xff0c;智能手机已经不仅仅是一个通讯工具&#xff0c;它更是我们生活中的一位全能伙伴。作为科技领域的佼佼者&#xff0c;小米公司再次引领潮流&#xff0c;推出了全新旗舰手机——小米14 ULTRA。这款手机不仅在性能上进行了全面升级&am…

spring boot3参数校验基本用法

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《spring boot实战》 &#x1f30a;山高路远&#xff0c;行路漫漫&#xff0c;终有归途。 目录 前置条件 前言 导入依赖 使用介绍 配置检验规则 开启校验 使用注意 全局异常捕获返回友好提示信息 常用的校…

LeetCode94.二叉树的中序遍历

题目 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 &#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2] 思路 中序遍历的顺序是左子树 -> 根节点 -> 右子树。因此&#xff0c;我们可以通过递归的方式遍历二叉树&…

Linux——进程替换

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、进程程序替换1、替换原理2、替换函数3、函数解释4、命名理解 二、用例测试1、execl测试2、…

C#分部类的应用:记录学生信息

目录 一、分部类及其用途 二、实例 再发一个分部类的应用&#xff0c;巩固一下。 一、分部类及其用途 C#中的部分类也被称为分部类。 C#中的部分类是一种将类的定义分成多个部分&#xff0c;每个部分都位于自己的文件中&#xff0c;然后在编译时合并在一起的机制。 部分类…

图像处理ASIC设计方法 笔记2 图像边界镜像处理

这本书是图像处理方面ASIC与DSP比较,讲了为什么要用ASIC做图像处理,它的特点和适用场景。读到第一章,(计算卷积的)工作窗口位于图像边界时镜像扩展后的情况。 输入仍然是逐行逐列串行图像数据流,但是在工作窗口内部,根据窗口中心像素的坐标判断窗口位于图像边界的具体位…

面试经典150题【11-20】

文章目录 面试经典150题【11-20】388.O(1) 时间插入、删除和获取随机元素238.除自身以外数组的乘积134加油站135.分发糖果42. 接雨水13.罗马数字12.整数 转 罗马数字58.最后一个单词的长度14.最长公共前缀151.反转字符串中的单词 面试经典150题【11-20】 388.O(1) 时间插入、删…

赞:java使用easy-excel导出数据的通用模板思路

我们在项目中都会有导入导出的功能&#xff0c;这篇文章主要是讲导出的&#xff0c;导入我会在另外一篇博客文章中讲解。 现在我们开始。 首先&#xff1a;需要在项目中的pom.xml中导入easy-excel的依赖 <!--使用esay-excel进行导入导出 --> <dependency><gr…

友点CMS image_upload.php 文件上传漏洞复现

0x01 产品简介 友点CMS是一款高效且灵活的网站管理系统,它为用户提供了简单易用的界面和丰富的功能。无论是企业还是个人,都能通过友点CMS快速搭建出专业且美观的网站。该系统支持多种内容类型和自定义模板,方便用户按需调整。同时,它具备强大的SEO功能,能提升网站在搜索…