数据结构与算法(位运算)
位运算
内存中的数据,最终的存储方式都是二进制,位运算就是对整数在内存的二进制位进行操作。
按位与 &
两个整数进行按位与运算,相同二进制位的数字如果都是是,则结果为1,有一个为0,则结果为0
下面是 3 & 7 的计算过程
二进制 整数
0 1 1 3
1 1 1 7
0 1 1 3(结果)
3 & 7 = 3
按位或 |
两个整数进行按位或运算,相同二进制位的数字如果有一个为1,则结果为1,都为0,则结果为0
下面是 5 | 8 的计算过程
二进制 整数
0 1 0 1 5
1 0 0 0 8
1 1 0 1 13(结果)
5 | 8 = 13
左移 <<
二进制向左移动n位,在后面添加n个0
下面的 3 << 1 的计算过程
二进制 整数
1 1 3
1 1 0 6
3<<1 = 6
练习:一组数,内容为 3,9,19,20 ,请用一个整数来表示这四个数
var value = 0 value = value | 1<<3 value = value | 1<<9 value = value | 1<<19 value = value | 1<<20 console.log(value)
程序输出结果为:1573384
bitmap
新的实现方式
经过前面一系列的分析和位运算学习,现在我们要重新设计一个类,实现 addMember 和 isExist 方法,用更快的速度,更少的内存
- 数据范围是0~100,那么只需要4个整数就可以表示 4 * 32 个数的存在与否(如果用普通的数组方法,需要数组中有100个数来表示0-100的存在与否),创建一个大小为4的数组
- 执行addMember时,先用 member/32,确定member在数组里的索引(arr_index),然后用 member%32,确定在整数的哪个二进制位进行操作(bit_index),最后执行 bit_arr[arr_index] = bit_arr[arr_index] | 1<<bit_index
- 执行isExist时,先用 member/32,确定member在数组里的索引(arr_index),然后用 member%32,确定在整数的哪个二进制位进行操作(bit_index),最后执行 bit_arr[arr_index] & 1<<bit_index ,如果结果不为 0 ,就说明 member存在
function BitMap(size){ var bit_arr = new Array(size) for(var i=0; i<bit_arr.length; i++){ bit_arr[i] = 0 } this.addMember = function(member){ // 决定在数组中的索引 var arr_index = Math.floor(member/32) // 决定在整数的32个bit位的哪一位上 var bit_index = member%32 bit_arr[arr_index] = bit_arr[arr_index] | 1<<bit_index } this.isExist = function(member){ // 决定在数组中的索引 var arr_index = Math.floor(member/32) // 决定在整数的32个bit位的哪一位上 var bit_index = member%32 var value = bit_arr[arr_index] & 1<<bit_index if(value !== 0){ return true } return false } }
概念
这种数据结构基于位做映射,能够用很少的内存存储数据,和数组不同,它只能存储表示某个数是否存在,可以用于大数据去重,大数据排序,两个集合取交集。
BitMap在处理大数据时才有优势,而且要求数据集紧凑,如果要处理的数只有3个:1,1000,100000,那么空间利用率太低了,最大的值决定了BitMap要用多少内存。
大数据排序
有多达10亿个无序整数,已知最大值为15亿,请对这10亿个数进行排序。(BitMap做排序有个前提,就是数据是不能重复的,如果有重复的就做不成了)
传统排序算法都不可能解决这个排序问题,即便内存允许,其计算时间也是漫长的,如果使用BitMap就极为简单。
BitMap存储最大值为15亿的集合,只需要180M 的空间,空间使用完全可以接受,至于速度,存储和比较过程中的位运算速度都非常快,第一次遍历,将10亿个数都放入到BitMap中,第二次,从0到15亿进行遍历,如果在BitMap,则输出该数值,这样经过两次遍历,就可以将如此多的数据排序。
为了演示方便,只用一个很小的数组,[0, 6, 88, 7, 73, 34, 10, 99, 22],已知数组最大值是 99 ,利用BitMap排序的算法如下
var arr = [0, 6, 88, 7, 73, 34, 10, 99, 22] var sort_arr = [] var bit_map = new BitMap(4) for(var i=0; i<arr.length; i++){ bit_map.addMember(arr[i]) } for(var i=0; i<=99; i++){ if(bit_map.isExist(i)){ sort_arr.push(i) } } console.log(sort_arr)
输出结果:[ 0, 6, 7, 10, 22, 34, 73, 88, 99 ]
布隆过滤器
前面所讲的BitMap的确很厉害,可以,却有着很强的局限性,BitMap只能用来处理整数,无法处理字符串,假设让你写一个强大的爬虫,每天爬取数以亿计的网页,那么你就需要一种数据结构,能够存储你已经爬取过的 url ,这样,才不至于重复爬取。
你可能会想到使用hash函数对url进行处理,转成整数,这样,似乎又可以使用 BitMap 了,但这样还是会有问题。假设BitMap能够映射的最大值是 M ,一个url的hash值需要对M求模,这样,就会产生冲突,而且随着存储数据的增多,冲突率会越来越大。
布隆过滤器的思想非常简单,其基本思路和BitMap是一样的,可以把布隆过滤器看做是 BitMap的扩展。为了解决冲突率,布隆过滤器要求使用k个 hash函数,新增一个 key时,把 key散列成 k 个整数,然后在数组中将这 k 个整数所对应的二进制位设置为1,判断某个key是否存在时,还是使用 k 个hash函数对key进行散列,得到k个整数,如果这k个整数所对应的二进制位都是1,就说明这个key存在,否则,这个key不存在。
对于一个布隆过滤器,有两个参数需要设置,一个是预估的最多存放的数据的数量,一个是可以接受的冲突率。
hash函数
哈希函数就是将某一个不定长的对象映射为另一个定长的对象,如果你对这个概念感到困惑,你就换一个理解方法,你给hash函数传入一个字符串,它返回一个整数。为了实现一个布隆过滤器,我们需要一个好的 hash函数,计算快,冲突又少
原文地址:https://www.cnblogs.com/haishen/p/11881935.html
- [Go语言]实现可以枚举的map
- GO语言常用的文件读取方式
- GO语言文件的创建与打开实例分析
- Go语言单链表实现方法
- Go语言实现AzDG可逆加密算法实例
- 剖析Go编写的Socket服务器模块解耦及基础模块的设计
- Golang中的sync.WaitGroup用法实例
- Go 语言实现 MapReduce 框架
- Performance Schema使用简介(一)
- golang 垃圾回收 gc
- Go语言服务器开发之简易TCP客户端与服务端实现方法
- 移动搜索SEO分享:PHP自动生成百度开放适配及360移动适配专用的Sitemap文件
- 分享两种外链跳转方法,可避免权重流失。
- go语言十大排序算法总结
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 原生node处理get和post请求
- 如何在Vue中自己实现v-model
- 【STM32F429】第1章 当前主流的小型嵌入式GUI
- 【Unity游戏开发】升级Unity2019后,资源管线后处理采坑记录
- Angular @Effect监听指定Action类型的实现原理
- SAP Spartacus shipping address页面请求1 - Address
- SAP Spartacus shipping address页面请求2.1 - setDefaultAddress
- SAP Spartacus只执行指定单元测试的小技巧
- SAP CDS view里将Date和time连接成timestamp的函数
- SAP CDS view里计算两个date & time字段间包含的seconds秒数
- SAP CDS view里的日期操作函数(往后推算X天得到新日期)
- SAP CDS view的日期格式转换,比如从YYYYMMDD转到DD/MM/YYYY
- SAP CDS view如何取得当前系统日期和系统时间戳
- Vue 父组件如何监听子组件的生命周期
- Django3+websocket+paramiko实现web页面实时输出