zoukankan      html  css  js  c++  java
  • 数据结构与算法分析 学习笔记 (4)

    散列(Hash)


    散列是以常数平均时间执行插入,删除,查找的技术;需要元素之间比较,排序的信息,如查找最大,最小值等等操作不被hash所支持;

    散列表关键的是设计哈希函数,运算简单并且在单元之间均匀的分配关键字,并减少碰撞;

     1 //分离连接散列表的类型声明
     2 #ifndef _HashSep_H
     3 
     4 struct ListNode;
     5 typedef struct ListNode *Position;
     6 struct HashTbl;
     7 typedef struct HashTbl *HashTable;
     8 
     9 HashTable InitializeTable(int TableSize);
    10 void DestroyTable(HashTable H);
    11 Position Find (ElementType Key,HashTable H);
    12 void Insert(ElementType Key,HashTable H);
    13 ElementType Retrieve(Position P);
    14 
    15 #endif        /*_HashTable_H声明*/
    16 
    17 struct ListNode
    18 {
    19     ElementType Element;
    20     Position Next;
    21 };
    22 
    23 typedef Position List;
    24 
    25 struct HashTbl
    26 {
    27     int TableSize;
    28     List *TheLists;//TheList 实际上是一个指向指向ListNode结构的指针的指针;
    29 };
    30 
    31 //初始化
    32 HashTable InitializeTable(int TableSize)
    33 {
    34     HashTable H;
    35     int i;
    36     if(TableSize<MinTableSize)
    37     {
    38         Erro("Table Size too small!");
    39         return NULL;
    40     }
    41     //分配hash表
    42     H=malloc(sizeof(struct HashTbl));
    43     if(H==NULL)
    44     {
    45         FataErro("Out of Space!");
    46     }
    47     H->TableSize=NextPrime(TableSize);//设置表的大小为以素数;
    48     //分配链表数组
    49     H->TheLists=malloc(sizeof(List)*H->TableSize);
    50     if(H->TheList==NULL)
    51         FataErro("out of space");
    52     //分配头结点
    53     for(i=0;i<H->TableSize;i++)
    54     {
    55         H->TheLists[i]=malloc(sizeof(Struct ListNode));
    56         if(NULL==H->TheList[i])
    57             FataErro("Out of space");
    58         else
    59             H->TheList[i]->Next=NULL;
    60     }
    61     return H;
    62 }
    63 // 分散链接表的Find操作
    64 Position Find (ElementType Key,HashTable H)
    65 {
    66     Position P;
    67     List L;
    68     L=H->TheLists[hash(Key,H->TableSize)];
    69     P=L->Next;
    70     while(NULL!=P&&P->Element!=Key)
    71         p=p->next;
    72     return p;
    73 }
    74 //分散链接表的Insert操作
    75 void Insert(ElementType Key,HashTable H)
    76 {
    77         List L;
    78         Position pos,NewCell;
    79         pos=Find(KEy ,H);
    80         if(Pos==NULL)//key在hash表中未找到
    81         {
    82             NewCell=malloc(sizeof(struct ListNode));
    83             if(NULL==NewCell)
    84                 FataErro("out of space");
    85             else
    86             {
    87                 L=H-TheLists[hash(Key,H->TableSize)];
    88                 NewCell->Next=L->Next;
    89                 NewCell->Element=Key;
    90                 L->Next=NewCell;
    91             }
    92         }
    93 }

     分离链接散列算法的缺点是需要指针,由于给新单元分配地址需要时间,因此这就导致算法速度的减慢,同时算法实际上还要求对另一种数据结构的实现;


     开放定址法

    常用的冲突解决的方法:线性探测法,平方探测法,双散列(两个散列函数)

    定理:如果使用平方探测,且表的大小是素数,那么当表至少有一半是空的时候,总能够插入一个新的元素。


    对于使用平方探测的开放定址散列法,如果表的元素填的太满,那么操作的运行时间将开始消耗过长,且Insert操作可能失败。这可能发生在有太多的移动和插入场合,此时解决的方法是建立另外一个大约两倍大的表,扫描整个原始散列表,计算每个元素的新散列表值并将其插入到新表中;此时产生了再散列。


    小结:

    散列表可以用来以常数时间实现Insert和Find操作。当使用散列表时,注意诸如装填因子细节特别重要;

    分散链接散列法:虽然装填银子不很大时,性能并不明显降低,但装填因子还是应该接近于1;

    对于开放定址法:除非完全不可避免,否则装填因子应该不超过0.5.如果使用线性探测,那么性能随着装填因子接近于1将急速下降;

    再散列运算可以通过使表增长(收缩)来实现,这样将会保持合理的装填因子;

    使用散列表可以不可能找出最小元素。除非准确知道一个字符串,否则散列表也不可能有效查找它。二叉查找树可以迅速找到在一定范围内的所有项,散列表是做不到的。。

    如果不需要有序的信息以及对输入的排序,那么就应该使用散列表;

    散列表的典型用途:1)、编译器使用散列表跟踪源代码中声明的变量。这种数据结构叫做符号表,2)在为游戏编制的程序中。当程序搜索不同的行时,它跟踪通过计算基于位置的散列函数而看到一些位置。如果同意的位置再出现。程序通常通过简单移动变换来避免昂贵的重复计算。游戏程序的这种一般特点叫做交换表。

    Edit By SolarJupiter
  • 相关阅读:
    安装项目管理工具 SVN+Redmine
    jquery validate
    NHibernate集合映射中的set, list, map, bag, array
    NHibernate执行原始SQL代码的方法小结 .
    一个简单的存储过程
    修改Project中的表名及字段名
    用代码修改类名
    实现Pick和Reigister
    转移单的装运和收货
    库存维度检查
  • 原文地址:https://www.cnblogs.com/HuaiNianCiSheng/p/3104124.html
Copyright © 2011-2022 走看看