数据结构第十一周笔记(4)—— 散列查找 (慕课浙大版本--XiaoYu)

196 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第26天,点击查看活动详情

11.4 散列表的性能分析

  1. 平均查找长度(ASL)用来度量散列表查找效率:成功、不成功

    1. 成功:查找的元素再散列表里
    2. 不成功:查找的元素不在散列表里
  2. 关键词的比较次数,取决于产生冲突的多少。影响产生充裕多少有以下三个因素:

    1. 散列函数是否均匀(不均匀的话冲突会多,性能就会差)
    2. 处理冲突的方法
    3. 散列表的装填因子α(装了多少元素,装的元素少那么冲突少。装的元素多则冲突多)

分析:不同冲突处理方法、装填因子对效率的影响

  1. 线性探测法的查找性能

    可以证明,线性探测法的期望探测次数满足下列公式:image-20220827214026405

image-20220827214455451

对于线性探测,如果当前装填因子值为0.654321, 此时不成功情况下的期望探测次数小于成功情况下的期望探测次数。错误

  1. 平方 探测法和双散列探测法的查找性能

    可以证明,平方探测法和双散列探测法探测次数 满足下列公式:image-20220827214621567

    image-20220828210649498

    ASCu:成功 ASLs:失败

期望探测次数与装填因子α的关系

横坐标:装填因子α

纵坐标:期望探测次数

当装填因子α<0.5的时候,各种探测法的期望探测次数都不大,也比较接近

合理的最大装入因子α应该不超过0.85(对线性探测来说)

image-20220828220419341

  1. 分离链接法的查找性能

    所有地址链表的平均长度定义成装填因子α,α有可能超过1

    不难证明:其期望探测次数p为:image-20220828224355504

总结

哈希查找(散列查找)特点

选择合适的h(key),散列法的查找效率期望是常数O(1),它几乎与关键词的空间的大小n无关!也适合于还建瓷直接比较计算机大的问题

优点:

  1. 不像搜索树一样或者平衡二叉树一样,他的查找基本上是跟问题的规模有关系。所以不发生冲突的话基本上是一次成功

特点:

  1. 跟问题规模无关,是一个常量时间
  2. 散列查找在很多情况下,用于字符串的管理(例如web地址名关键词搜索这种字符串管理),关键词查找
  3. 它是以较小的α为前提。因此,散列方法是一个以空间换时间
  4. 散列方法的存储对关键字是随机的,不便于顺序查找关键字,也不适合于范围查找,或最大值最小值查找

开放地址法

优:散列表是一个数组,存储效率高,随机查找

缺:散列表有"聚集"现象

分离链法

优:关键字删除不需要"懒惰删除"法,从而没有存储"垃圾"

缺:散列表是顺序存储和链式存储的结合,链表部分的存储效率和查找效率都比较低

太小的α可能导致空间浪费,大的α又将付出更多的时间代价。不均匀的链表长度导致时间效率的严重下降

11.5 应用实例:词频统计

【例】给定一个英文文本文件,统计文件中所有单词出现的频率,并输出词频最大的前10%的单词及其词频。
        假设单词字符定义为大小写字母、数字和下划线,其它字符均认为是单词分隔符,不予考虑。
​
【分析】关键:对新读入的单词在已有单词表中查找,如果已经存在,则将该单词的词频加1,如果不存在,则插入该单词并记词频为1。
​
如何设计该单词表的数据结构才可以进行快速地查找和插入?散列表
int main(){
    int TableSize = 10000;//散列表的估计大小
    int wordcount = 0,length;
    HashTable H;
    ElementType word;
    FILE*fp;
    char document[30] = "HarryPotter.txt";//要被统计词频的文件名
    H = Initialize Table( TableSize );//建立散列表(也就是初始化散列表)
    if((fp = fopen(document,"r")) == NULL) FatalError("无法打开文件!\n");
    while(!feof(fp)){//对文件进行处理,读到不是字母跟数字或者下划线而是分隔符的话,那就返回,获得到一个完整的word
        length = GetAWord(fp,word);//从文件中读取一个单词
        if(length > 3){//只考虑适当长度的单词
            wordcount++;//统计文件中单词总数
            InsertAndCount(word,H);//插入哈希表
            //InsertAndCount这个函数作用:到哈希表里去找这个元素单词在不在,不在就插入,如果在就词频加1
        }
    }
    fclose(fp);
    printf("该文档共出现%d个有效单词,",wordcount);
    Show(H,10.0/100);//显示词频前10%的所有单词
    //Show一共两个参数,一个是我们的散列表,另外一个是我们的要求词频前10%
    //这个函数一共做4件事情:1.统计最大词频;2.用一组数统计从1到最大词频的单词数;3.计算前10%的词频应该是多少;4.输出前10%词频的单词
    DestroyTable(H);//销毁散列表
    return 0;
}