哈希表及其经常使用算法(代码实例)

<hash表的特性>算法

    Hash 表是使用 O(1) 时间进行数据的插入删除和查找,可是 hash 表不保证表中数据的有序性,这样在 hash 表中查找最大数据或者最小数据的时间是 O(N) 。数据结构

<寻址和 hash 函数>

    理想状态下 hash 足够大,每一数据保存在一个 hash 存储单元内,这样对于插入删除和查找某一个数据就能够直接获得。可是现实状况下 hash 表不可能无限大,并且理论上保存的数据的个数是没有限制的,这样保存的数据的数量就远远大于 hash 表的存储单元的数量。函数

    为了实如今 O(1) 内对数据进行插入删除和查找,就必须将一个数据映射到 hash 表中的固定位置,这个映射函数就是 hash 函数。 Hash 函数经过对数据进行计算获得一个在 hash 表中的位置地址。oop

 

   图 1.1 理想的 hash 表大数据

      要选择较好的 hash 函数,以及 hash 表存储单元的数量,这样才能使保存在 hash 表中的数据均匀分布。理想状态不太可能实现,因为存储的数据数量远远大于 hash 表存储单元的数量,因此再好的 hash 函数也可能使不一样的数据获得相同的映射位置,这就形成了冲突。可是好的 hash 函数能够将这种冲突降到最低。spa

<分离连接>

         解决这种冲突的第一种方法是借助链表来实现,就是将数据实际存放在与 hash 表存储单元相连接的链表中,而不是 hash 的存储单元中。.net

 

图 2.1 分离链表code

     当产生冲突的时候,将两个数据都连接在同一 hash 存储单元保存的链表中。当一个存储单元保存的链表中有多个数据的时候,对于链表后面的数据的查找添加和删除就是否是严格意义上的 O(1) 了。一个好的 hash 函数可使得这个链表很短。最坏状况下,当全部的数据都保存在一个 hash 单元指定的链表中的时候,那么这个 hash 就和链表同样了。orm

<开放地址>

         使用开放地址方法解决冲突的时候,数据仍然保存在 hash 表的存储单元中,可是当冲突发生的时候,要再次计算新的地址。blog

         经常使用的开放地址法是线性探查,就是当对一个数据进行插入删除或者查找的时候,经过 hash 函数计算,发现这个位置不是要找的数据,这时候就检查下一个存储单元,一直找到要操做的数据为止。

         除了线性探查外还有二次探查,再 hash 等等方法,都是当一次计算获得的位置不是要找到的数据的时候,怎样再次肯定新的位置。

<彻底 hash 表>

         采用分离链表的方式解决冲突的时候,当多个数据被映射到一个地址的时候,它们就造成了一个链表,要操做这其中的一个数据,那么就必须在这个链表中进行操做。若是 hash 函数选择的好的话,链表会很短,这样的操做近似 O(1) ,但并非精确的等于 O(1) ,它与链表的长度有关。对于数据的访问的最坏状况的访问也是 O(1) 的 hash 叫作彻底 hash 表。

         这样的 hash 表是一个两级的 hash 表,第一级的 hash 与使用分离连接方法的 hash 同样,可是 hash 存储单元中指向的不是一个链表,而是另外一个 hash 表。

 

图 4.1 彻底 hash 表

         要当心的选择一级以及二级的 hash 函数能够彻底保证在二级 hash 表中不会出现冲突。

经常使用算法

直接定址法 :地址集合 和 关键字集合大小相同

数字分析法 :根据须要hash的 关键字的特色选择合适hash算法,尽可能寻找每一个关键字的 不一样点

平方取中法:取关键字平方以后的中间极为做为哈希地址,一个数平方以后中间几位数字与数的每一位都相关,取得位数由表长决定。好比:表长为512,=2^9,能够取平方以后中间9位二进制数做为哈希地址。

折叠法:关键字位数不少,并且关键字中每一位上的数字分布大体均匀的时候,能够采用折叠法获得哈希地址,除留取余法除P取余,能够选P为质数,或者不含有小于20的质因子的合数

随机数法:一般关键字不等的时候采用此法构造哈希函数较恰当。

 

实际工做中须要视不一样的状况采用不一样的hash函数

考虑因素:计算哈希函数所须要的时间,硬件指令等因素。

关键字长度

哈希表大小

关键字分布状况

记录查找的频率。(huffeman树)

具体代码以下

 
#include<stdlib.h>  
#include<math.h>  
struct HashTable;  
struct ListNote;  
typedef struct HashTable *HashTbl;  
typedef struct ListNote *Position;  
typedef Position List;  
int Hash(int key,int tablesize);  
int NextPrime(int x);  
HashTbl InitalizeTable(int TableSize);  
void DestroyTable(HashTbl H);  
Position Find(int key,HashTbl H);  
void Insert(int key, HashTbl H);  
void Delete(int key,HashTbl H);  
struct HashTable{   
    int TableSize;  
    Position *TheList;  
};  
struct ListNote{  
    int element;  
    Position next;  
};  
int Hash(int key,int tablesize){  
    return key%tablesize;  
}  
int NextPrime(int x){  
    int flag;  
    while(1){  
        flag = 0;  
        int i;  
        int n = sqrt((float)x);  
        for(i = 2 ;i <= n;i++){  
            if(x % i == 0){  
                flag = 1;  
                break;  
            }  
        }  
        if(flag == 0)  
            return x;  
        else  
            x++;  
    }  
}  
HashTbl InitalizeTable(int TableSize){  
    if(TableSize <= 0){  
        printf("散列大小有问题\n");  
        return NULL;  
    }  
    HashTbl table = (HashTbl)malloc(sizeof(struct HashTable));  
    if(table == NULL)  
        printf("分配失败");  
    table->TableSize = NextPrime(TableSize);  
    table->TheList = (Position*)malloc(sizeof(List) * table->TableSize);  
    if(table->TheList == NULL)  
        printf("分配失败");  
    table->TheList[0] = (Position)malloc(table->TableSize*sizeof(struct ListNote));  
    if(table->TheList == NULL)  
        printf("分配失败");  
    int i;  
    for(i = 0;i < table->TableSize;i++){  
        table->TheList[i] = table->TheList[0] + i;  
        table->TheList[i]->next = NULL;  
    }  
    return table;  
}  
Position Find(int key,HashTbl H){  
    Position p;  
    List L = H->TheList[Hash(key,H->TableSize)];  
    p = L->next;  
    while(p != NULL && p->element != key)  
        p = p->next;  
    if(p == NULL)  
        return L;  
    else  
        return p;  
}  
void Insert(int key,HashTbl H){  
    Position p,NewCell;  
    p = Find(key,H);  
    if(p->element != key){  
        NewCell = (Position)malloc(sizeof(struct ListNote));  
        if(NewCell == NULL)  
            printf("分配失败");  
        else{  
            p = H->TheList[Hash(key,H->TableSize)];  
            NewCell->next = p->next;  
            p->next = NewCell;  
            NewCell->element = key;  
        }  
    }  
    else  
        printf("已经存在该值了\n");  
}  
void Delete(int key,HashTbl H){  
    Position p ,NewCell;  
    p = Find(key,H);  
    if(p->element == key){  
        NewCell = H->TheList[Hash(key,H->TableSize)];  
        while(NewCell->next != p)  
            NewCell = NewCell->next;  
        NewCell->next = p->next;  
        free(p);  
    }  
    else  
        printf("没有该值");  
}  
int main(){  
    HashTbl table = InitalizeTable(10);  
    Position p = NULL;  
    p = Find(10,table);  
    printf("%d\n",p->element);  
    Insert(55,table);  
    Insert(90,table);  
    Insert(35,table);  
    Insert(33,table);  
    p = Find(55,table);  
    printf("%d\n",p->element);  
    p = Find(33,table);  
    printf("%d\n",p->element);  
    Delete(33,table);  
    Delete(44,table);  
    system( "pause" );  
    return 0 ;  
}  

 

 
 
 

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

相关文章
相关标签/搜索