刁肥宅数据结构课设:布隆过滤器的实践与应用(V1.0)

课程编号:                     课程性质:   

 

 

 

数据结构课程设计报告

 

 

 

 

学院:         合肥工业大学           

班级:         物联网工程17-2       

姓名:         刁肥宅              

学号:         201721800X          

教师:         周波                

 

 

 

 

 

2018年 8月 10日   至  2018年 8 月 18日

第一章 理论基础

1.1 课题背景

在学习和工作中,时常需要使用到文本编辑器进行文档或者代码的编写。而文档和代码的编写中,常常会出现类似”true”和”ture”,”main”和”mian”等等的混淆,在程序排查错误和文档阅读中,造成不小的麻烦。因此,常用的文本编辑器例如Microsoft Word,Microsoft Visual Studio Code,Code::block等等通常都会附带有拼写检查和关键词高亮的功能。其原理是,通过引入默认的词典,记录该词典中的所有字符串,和当前文档进行比对,从而发现错误的代词或者代码关键字,并且采用下划线,文本高亮等形式来提醒用户。甚至于在用户输入某个关键词的前几个字符时,自动提示补全关键字。

然而,如果直接记录词典中的所有字符串并且用以遍历比对,会极大程度地加大空间和时间的复杂度。因此,在拼写检查器UNIXspell-checkers中,就采用了布隆过滤器(Bloom Filter, BF)数据结构的哈希表来判断某个字符串是否存在于词典中。

因此,本课程设计将使用Qt来设计文本编辑器,并建立以布隆过滤器作为词典存储的数据结构,以此实现拼写检查的功能。同时,该软件将支持添加关键字功能,以满足用户多变的需求。

本文将以如下顺序进行阐述:第一章将介绍该课程设计的理论基础,包括数据存储结构原理,程序设计框架等,第二章将介绍该课程设计的程序细节以及效果展示,第三章则将讨论和分析本次试验结果。

1.2 布隆过滤器

布隆过滤器是在1970年被巴顿布隆提出的,用来解决数据存储问题的哈希表。它将数据的存储形式由诸多字符串组成的数组,变为一个二进制向量序列,极大减小了检索和存储的难度。哈希表又称为散列表,是实现字典操作的一种有效数据结构。尽管在最坏情况下,散列表中查找一个元素的时间与在链表中查找的时间相同,达到了Θ(n)。然而在实际应用中,散列表查找的性能是极好的。在一些合理的假设下,在散列表中查找一个元素的平均时间是O(1)。

布隆过滤器的原理如下:初始化一个n字节二进制向量Array全部置为0,对于每个希望存储的字符串str1,通过x个哈希函数(又称散列函数)获取取值在[0, n)的哈希值序列H,然后依次将Array中的第Hi个字节置为1,则完成了对该字符串str1的存储。因此,同样地,对于希望检索的字符串str2,通过相同的哈希函数获取得到哈希值序列H’,显然,当该序列已被存储时,该哈希值序列在Array中对应的每一个字节都应该为1。图1.1展示了该结构的原理。

图1.1       布隆过滤器原理

所以,布隆过滤器的索引时间复杂度只和散列函数个数有关而与数据存储量大小无关;散列函数本身也彼此独立,利于并行计算,因而在各种数据结构之中脱颖而出。而它的缺点也同样地明显,首先,它不能删除已存储的元素。其次,对于某些本未被存储的字符串和已存储若干个字符串共m个字节的二进制向量,可能会存在一定概率导致未被存储的字符串被误判为已存储。

因此,有两种方法来尽量减小误判问题带来的影响:第一,减小误判率p,即使用较大容量的Array从而提高n,使用较多个哈希函数从而提高x,避免在同一个布隆过滤器中存储过多的字符串从而减小x。然而,这些方法都会一定程度上牺牲字符串存储的效率;第二,建立布隆过滤器白名单,对于那些未被存储而被误判为已被存储的字符串,加入到该白名单中,然而该白名单会对于布隆过滤器的检索,添加功能造成很多麻烦。因此,这两种方法都不能从根本上消除布隆过滤器的误判率。

尽管如此,布隆过滤器仍是一个相对而言,高效而鲁棒的数据存储结构,也是本次课程设计的研究重点。

1.3 Qt

Qt是一个跨平台C++图形用户界面应用程序开发框架,可以非常方便地用于开发GUI程序。本次课程设计将Qt用于文本编辑器的开发,并采用Qt Creator作为程序开发环境。

程序主要使用了QTextEdit控件以满足复制、粘贴、剪切、删除、撤销等文本编辑器基本功能,和QSyntaxHighlighter库以对满足规则的文本对象进行高亮。

第二章 程序设计

2.1 文本编辑器设计

本程序使用QTextEdit控件设计文本编辑器,并继承QSyntaxHighlighter类编写子类myHighLight类以实现高亮功能。

用户通过QTextEdit控件输入文本,并将文本传至myHighLight类的构造函数用以初始化。在该构造函数中,同时初始化了QRegExp*类型变量rule以匹配关键字用并使用QTextCharFormat类型变量format高亮。文本编辑器的界面如图2.2所示。

图2.2       文本编辑器

值得一提的是,该文本编辑器同时也支持了复制、粘贴、剪切、删除、撤销等等文本操作功能。

2.2 布隆过滤器设计

布隆过滤器设计的关键主要在两方面:第一,布隆过滤器的参数如散列函数个数x,二进制数组比特位数n等等;第二,散列函数的设计。

为了将误判率控制在1%以下,取散列函数个数x = 7,而比特位数n = 10*m,其中m为预计希望保存的关键字个数(具体推导过程见3.1节)。该程序内置了近百个C/C++关键字,经过一定的建模分析后,预计希望最终保存的关键字为8000个。因此,n = 80000字节,以大小为10000的unsigned char类型数组形式保存。

理论上优秀的散列函数应该包含下列性质: 1.哈希得到的值均匀分布在0-n上;2.各个哈希函数之间彼此独立,各个字符串得到的哈希值彼此独立。因此该程序的哈希函数设计宗旨是,1.获得尽量大的数值后取余,从而确保哈希值能够均匀分布。2.各个哈希函数之间无耦合关系,从而保证独立性。

因此,在myHighLight类被构造的同时,开辟一个大小为10000的unsigned char类型数组内存空间,并全部初始化为0。

2.3 添加关键词功能设计

对布隆过滤器的操作功能包括查找关键字isKeyExisted和添加关键字appendKey两个部分。

对关键字的查找即使判断该字符串在散列函数中获得的每个哈希值hash是否满足二进制阵列BloomFilter的第hash个字节位置处是否为1,即,BloomFilter[hash/8] >> hash%8) % 2 == 1,当任一哈希值不满足时,则认为该关键字不存在。而在文本编辑器中,首先使用正则表达式rule提取出文本中的所有单词,而仅当该单词被存储为关键字时,将该段文本高亮。

添加关键字之前首先应该使用正则表达式判断该段文本是否为单词,然后判断该关键字是否已经存在,虽然将该字符串在散列函数中获得的每个哈希值hash处对应的二进制阵列BloomFilter的第hash个字节位置处的所有0置为1,即 BloomFilter[code/8] += 1 << code%8。使用该方法,程序内置了C++17的所有关键字,如表2.1所示。


asm


do


if


return


typedef


auto


double


inline


short


typeid


bool


dynamic_cast


int


signed


typename


break


else


long


sizeof


union


case


enum


mutable


static


unsigned


catch


explicit


namespace


static_cast


using


char


export


new


struct


virtual


class


extern


operator


switch


void


const


false


private


template


volatile


const_cast


float


protected


this


wchar_t


continue


for


public


throw


while


default


friend


register


true

 

delete


goto


reinterpret_cast


try

 

表2.1 程序内置的所有关键字

在此基础上,该文本编辑器就具有了一定的编辑c++代码功能,效果如图2.3所示。

图2.3 程序效果展示

程序可以添加选定内容为关键字,从而一劳永逸地高亮该文本,人为添加关键词后,应自动重新对整段文本进行关键词检测。如图2.4所示。

图2.4 添加关键字

第三章 结果分析

3.1 布隆过滤器的鲁棒性分析

布隆过滤器的鲁棒性分析即对布隆过滤器的误判率进行分析。正如前文所说,布隆过滤器的误判率不可避免,因此只能设置阈值1%,通过参数的设计,将布隆过滤器的理论误判概率降低到阈值以下。

首先假设哈希函数为理论完美的,即哈希后得到的值符合均匀分布,那么每个字符串的每个哈希值都会等概率地生成在二进制数组的n个比特位上,并且彼此独立。那么,基于此假设,插入单个哈希值时,一个特定比特位没有被激活,即置为1,的概率为p0 = 1 – 1/n。字符串对应了x个哈希值,由于哈希值之间彼此独立,则在插入单个字符串后,该比特位没有被激活的概率为p1 = p0x。而插入k个字符串后,同理该比特位没有被激活的概率为p2 = p1k,反之它被激活的概率就为p2’ = 1 - p2。而误判现象即对于一个未被存储的元素,x个对应的比特位均被激活的概率,故误判率为P = (p2’)k,由于1/m趋近于0,故P可以简化为:

P =  (p2’)k  =  (1 - p2)k = (1 – (1 – 1/n) kx)k =(1 – e-kx/nk

在给定的x和n下,对等式两边同时取对数按k求导,最小化P得到k = (n/x)ln2,此时ln P = -(n/x)ln22。对于P<0.01,有n/x>9.6,而k = 6.72。因而,在本程序的布隆过滤器中,取哈希函数共7个,二进制数组字节数为80000。

3.2 运行复杂度分析

布隆过滤器作为数据结构时,添加和查找关键词的运算复杂度极低,而相应的删除关键词的成本相当高。

布隆过滤器删除关键词通常采用引入白名单的方式,假设白名单共m个字符串,则遍历白名单的复杂度约为O(m*s),其中s为字符串平均长度。由于查找关键词前必须遍历白名单,因此复杂度为O(x)+O(m*s),其中x为散列函数个数;而添加关键词前必须要先查找关键词,故运算复杂度为O(2*x)+O(m*x)。同样地,布隆过滤器的空间复杂度具有类似的情况,布隆过滤器对内存的占用分为两部分,第一,白名单存储,复杂度约为O(m*s);第二,二进制数组存储,复杂度约为O(n)。合计为O(m*s)+ O(n)

原文地址:https://www.cnblogs.com/25th-engineer/p/9710457.html

时间: 2024-10-13 20:18:22

刁肥宅数据结构课设:布隆过滤器的实践与应用(V1.0)的相关文章

刁肥宅数据结构课设“布隆过滤器的实践与应用”源代码(v1.0,永不上交)

代码很简单,写了一些注释:加上注释看就很清楚了. 文件bloomfilter.cpp: 1 #include "bloomfilter.h" 2 3 // return a hash range from 0 to 79999 4 int hash(const char* str, int index) 5 { 6 int hash = 1; 7 int seed = 12345; 8 int curr; 9 switch(index) 10 { 11 case 0:{ 12 whil

ATM取款机模拟——数据结构课设

今天帮人写的第二篇课设 , ;-) 机智的窝 要求:大概说一下吧,就是要创建一个用户(初始化一账户),模拟ATM的业务(取款,100的整数倍,改密               码,查余额,等等,各种简单繁琐的操作 ;-) ) 直接贴代码吧: #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <string> using name

排序算法及其比较--数据结构课设

 排序算法及其比较 课程设计报告 一. 设计内容 编程实现希尔.快速.堆排序.归并排序算法,并利用程序统计每种算法的执行时间.要求随机产生10000(或50000. 100000. 200000,由用户选择)个数据存入数据文件,然后读数据文件,分别采用不同排序方法进行排序,将结果存入另一个文件中. 二. 设计思想描述 1.  总思想 本程序采用模块化设计思想,分为产生随机数模块,计时模块,写入磁盘模块,读出磁盘模块,希尔排序模块,快速排序模块,堆排序模块,归并排序模块,计时模块.对常见的4 种经

数据结构课设——有向图的深度、广度优先遍历及拓扑排序

任务:给定一个有向图,实现图的深度优先, 广度优先遍历算法,拓扑有序序列,并输出相关结果. 功能要求:输入图的基本信息,并建立图存储结构(有相应提示),输出遍历序列,然后进行拓扑排序,并测试该图是否为有向无环图,并输出拓扑序列. 按照惯例,先上代码,注释超详细: #include<stdio.h> #include<stdlib.h> #include<malloc.h> #pragma warning(disable:4996) #define Max 20//定义数

数据结构课设

p127 kmp字符串匹配算法 查找串a在串b中出现了多少次 时间复杂度o(n) http://paste.ubuntu.com/13771972/ 测试数据 5HAHAHAHAWQNWQNADAADADADABABABBBABABABABABABABABBDADADDAADAADDAAADAAD P199堆排序 输入A代表将元素加入堆,T代表输出并取走堆中的最大元素 时间复杂度nlgn代码http://paste.ubuntu.com/13773221/ 测试数据 5A 77751A 1329

刁肥宅详解中缀表达式求值问题:C++实现顺序/链栈解决

1. 表达式的种类 如何将表达式翻译成能够正确求值的指令序列,是语言处理程序要解决的基本问题,作为栈的应用事例,下面介绍表达式的求值过程. 任何一个表达式都是由操作数(亦称运算对象).操作符(亦称运算符)和分界符组成的.通常,算术表达式有3种表示: ①中缀(infix)表示:<操作数><操作符><操作数>,如A+B. ②前缀(prefix)表示: <操作符><操作数><操作数>,如+AB. ③后缀(postfix)表示: <操作

漫画app课设

Android移动应用开发 课程设计报告 (2019—2020学年 第Ⅰ学期) 作品主题:漫画app 系    别        信息与控制工程 专    业        计算机科学与技术 班    级          计算机1702 学    号            173230217 姓    名               张宏升 指导教师               郭丹 目录 一.需求分析 1 1.1引言 1 1.1.1编写目的 1 1.1.2项目背景 1 1.2功能需求分析 1

布隆过滤器--空间效率很高的数据结构

一.先谈哈希 1.1原理 Hash (哈希,或者散列)函数在计算机领域,尤其是数据快速查找领域,加密领域用的极广. 其作用是将一个大的数据集映射到一个小的数据集上面(这些小的数据集叫做哈希值,或者散列值). 1.2一个典型的hash函数示意图 1.3特点 如果两个散列值是不相同的(根据同一函数),那么这两个散列值的原始输入也是不相同的.散列函数的输入和输出不是唯一对应关系的,如果两个散列值相同,两个输入值很可能是相同的.但也可能不同,这种情况称为 “散列碰撞”(或者 “散列冲突”). 1.4缺点

【数据结构】位图BitMap、布隆过滤器的算法实现

我们先给出之前我看过的腾讯公司的一道笔试题,引出位图BitMap. 给40亿个不重复的无符号整数,没排过序.给一个无符号整数,如何快速判断一个数是否在这40亿个数中. 这个问题怎么解决呢? 1)将40亿数据保存起来(保存在数组.链表.树中),再和该数判断是否相等. 那我们思考一下需要多少内存: 2)借助位图BitMap解决. 位图(BitMap) 是用一个数组中的每个数据的每个二进制位表示一个数是否存在.1表示存在,0表示不存在. 相当于把数组分成很多块的空间,每一块是32个比特位. 原来32个