算法之个人总结:Hash表之简单应用.doc_第1页
算法之个人总结:Hash表之简单应用.doc_第2页
算法之个人总结:Hash表之简单应用.doc_第3页
算法之个人总结:Hash表之简单应用.doc_第4页
算法之个人总结:Hash表之简单应用.doc_第5页
全文预览已结束

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

算法之个人总结:Hash表之简单应用 前段时间看了个微软编写的C库函数,在这个库函数里学到一个自我感觉相当牛比的小算法,说白了是Hash表的应用。大家都知道,Hash表最主要是用来实现查找功能的,再具体点是用常量级时间复杂度找到你想查找的东西。首先,我以一个小问题引入将要介绍的Hash算法,问题如下:现有字符串str1,str2,编写一个函数返回str1中有多少个字符在str2字符串中。其实这个函数也很简单(假如我们不考虑时间复杂度的话),遍历str1字符串,其中对于str1中的每一个字符都要去判断是否在str2字符串中,如果在统计变量加1,即需要两个for循环,即时间复杂度为0(LenA*LenB),程序也很简单,如下:/返回字符串str1中有多少个字符在str2字符串中intCharCount(constchar*str1,constchar*str2)intct=0;constchar*ptr;for(;*str1!=0;+str1)/每次从str2的开头开始遍历for(ptr=str2;*ptr!=0;+ptr)if(*str1=*ptr)/如果发现str1当前字符在str2字符串中+ct;break;returnct;这个程序每次判断str1中的字符是否在字符串str2中时,str2字符串均需要从开头遍历,即每次需要回溯,从而使得整个算法的时间复杂度很高,那么我们是否可以用常量级时间复杂度来执行上面程序的内循环?即我们是否可以用常量级时间复杂度来判断某字符是否在字符串str2中?答案是肯定的,此时就需要Hash表。首先我先叙述下关于这个思路微软的算法是什么。即如何用常量级时间复杂度来判断一个字符是否在某个字符串中。首先我们先解决这个问题,你能否按照某种映射方式将256个字符一一映射到一个数组里,换句话说已知chararr32,你能否将256个字符映射到这个数组里?我们都知道ASCII值总共是256个(即28),如果我们将这256个字符分组,每组字符个数是8,那么可以分256/8组,即32组,因此对于ASCII值为c的字符,它属于编号为c/8的组(组的编号是0-31),因此,我们可以建立一个含有32个元素的数组,编号相同的8个字符存放在一个单元,在一个单元里如何来区分这8个字符呢?如果接着分析下去,易知,每一组中的8个字符除以8的余数均是0-7,因此,我们可以根据这8个字符除以8的余数来分别区分它们,具体办法如下:用一个char类型数据,char类型数据的最低位来表示除以8余数是0的那个字符,倒数第二位表示除以8余数是1的字符,从而可以将每一组中的8个字符用一个char类型数据的每一位表示。例如:ASCII值是49的字符应该这样存放在Hash表中(含有32个元素的数组),首先49/8等于6即编号是6,其次49%8等于1,即这个单元的char数据的bit1位是1,即arr6中的char数据的二进制应该为00000010;有了上述算法的思想,那么我们就可以用chararr32来存放一个字符串str2了,依次遍历这个字符串,按照上述原则依次标记数组中相应位置,字符串str2中每一个字符c的位置是arrc/8,其次使得该char数据的第c%8bit置1,假如arr数组中每一个元素初始值均为0,那么可以这样实现:/使得编号为c/8的单元中的char数据的第c%8bit置1arrc/8=arrc/8|(1(c%8);如果将str2中的每一个字符按照上述原则标记好了,假如我们要在str2中查找字符a,那么可以判断编号为a/8的单元中的char数据的第a%8bit是否为1,如果是说明字符a在str2中,即:if(arra/8&(1(a%8)!=0)/说明字符a存在的看看利用这种方法是不是实现了常量时间复杂度查找某字符是否在字符串中?嘿嘿!重新回到开头的那个问题,判断str1中的字符是否在str2中,查找算法就可以用上述思路来实现,即只需要遍历str1字符串,之后用上述常量时间复杂度的查找算法判断str1当前字符是否在str2中,易知时间复杂度是O(LenA),算法如下:intCharCount_(constchar*str1,constchar*str2)charhash32;/hash表的初始化for(inti=0;i32;+i)hash=0;/用hash保存str2中所有字符constchar*pstr2=str2;for(;*pstr2!=0;+pstr2)hash*pstr2/8|=(1(*pstr2%8);intct=0;/遍历str1字符串,判断每个字符是否在hash表中(是否在str2字符串中)for(;*str1!=0;+str1)if(hash*str1/8&(1(*str1%8)+ct;returnct;其实上述算法还可以加快,我们都知道计算机在处理除法以及取模运算时相对是较慢的,因此我们可以用位运算来实现上面的除法和取模运算,*str1/8等价于*str13,另外,一个数N除以2m的余数实际上是N的低mbit位所表示的十进制数,即*str1%(23)等价于*str1&7(具体可以自己想),因此上述算法的极限代码是:intCharCount_(constchar*str1,constchar*str2)charhash32;/hash表的初始化for(inti=0;i32;+i)hash=0;/用hash保存str2中所有字符constchar*pstr2=str2;for(;*pstr2!=0;+pstr2)hash*pstr23|=(1(*pstr2&7);/优化之一intct=0;/遍历str1字符串,判断每个字符是否在hash表中(是否在str2字符串中)for(;*str1!=0;+str1)if(hash*str13&(1(*str1&7)/优化之二+ct;returnct;至此,整个算法已经详细给出。总结:1)看到此不知道你是否彻底理解了上述Hash表的建立,其实细心的读者可能会提出这样的问题,为什么把256个字符分成32组(每组只存放8个字符)?呵呵,其实不一定非得分成32组,也可以分成16组,也可以分成8组,。其实算法的本质是在内存中用256bits来表示这256个字符是否存在,我们完全可以分成16组,每一组用16bit来表示,即shortarr16;或者分成8组,即intarr8,自己可以实现下。2)现在你能否实现一个这样的函数:size_tstrspn(constchar*s,constchar*aept);函数说明:strspn()从参数s字符串的开头计算连续的字符,而这些字符都完全是aept所指字符串中的字符。简单的说,若strspn()返回的数值为n,则代表字符串s开头连续有n个字符都是属于字符串aept内的字符,即字符串s中第n+1个字符不属于aept字符串中,要求时间复杂度为0(N)(嘿嘿,其实这就是一个C库函数,相信你时间复杂度为0(N*N)的算法马上就能写出来吧)3)回顾文章开始那个问题,其实是利用了空间换取时间的思想,即增加了算法的空间复杂度(因为我们额外建立了一个Hash数组),但是算法的时间复杂度变成了O(N),因此在内存空间不是问题的情况下,利用这种增加空间复杂度换取时间复杂度的思想值得我们去考虑。4)如果你足够细心,那么利用本篇介绍的Hash算法,你此时一定能将C库函数strtok实现出来,个人认为这个库函数是字符串库函数中最最难的一个,不仅其功能难理解,实现起来也很困难,呵呵,其实我就是在看微软编写的strtok源码的时候才发现了本篇这个hash算法的,哈哈,strtok这个函数一定要去看哦,诺西两年笔试题目均从不同角度考察了该函数的实现。总结2)strspn函数代码补充:/算法时间复杂度为O(Len1*Len2)intMyStrspn(constchar*str1,constchar*str2)constchar*temp;intct=0;/非法输入if(str1=NULL|str2=NULL)returnct;for(;*str1!=0;+str1)/每次令temp指向str2字符串开头,来判断*str1是否在字符串str1中for(temp=str2;*temp!=0;+temp)if(*str1=*temp)/*str1在字符串str2中,那么停止break;if(*temp=0)/如果遍历完str2了(说明*str1不在str2中)break;else+ct;returnct;/时间复杂度为O(Len1)intMyStrspn_(constchar*str1,constchar*str2)/非法输入if(str1=NULL|str2=NULL)return0;/分成16组,每组是16bits(2字节)shortHash16;/hash表的初始化for(inti=0;i16;+i)Hash=0;/将str2字符串每一个字符映射到数组Hash中constc

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论