hash学习

目录

1、哈希函数

2、哈希冲突(Hash collision)

3、链地址法代码

4、链地址法 hash表实战:1418. 点菜展示表


转自这里:https://blog.csdn.net/txl199106/article/details/40184965

哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。具体的介绍网上有很详细的描述,如闲聊哈希表 ,这里就不再累述了;

哈希表在像Java、C#等语言中是与生俱来的。可是在C的世界中,似乎只有自己动手,丰衣足食;在网上google了一把,大致有几个版本,我会一一来分析对比;

首先先来交代一下哈希表实现中需要注意的一些概念:

 

1、哈希函数


也叫散列函数,即:根据key,计算出key对应记录的储存位置
position = f(key)

散列函数满足以下的条件:

1、对输入值运算,得到一个固定长度的摘要(Hash value);

2、不同的输入值可能对应同样的输出值;

以下的函数都可以认为是一个散列函数:

f(x) = x mod 16; (1)

f(x) = (x2 + 10) * x; (2)

f(x) = (x | 0×0000FFFF) XOR (x >> 16); (3)

不过,仅仅满足上面这两条的函数,作为散列函数,还有不足的地方。我们还希望散列函数满足下面几点:

1、散列函数的输出值尽量接近均匀分布;

2、x的微小变化可以使f(x)发生非常大的变化,即所谓“雪崩效应”(Avalanche effect);

上面两点用数学语言表示,就是:

1, 输出值y的分布函数F(y)=y/m, m为散列函数的最大值。或记为y~U[0, m]

2,|df(x)/dx| >> 1;

从上面两点,大家看看,前面举例的三个散列函数,哪个更好呢?对了,是第三个:

f(x) = (x | 0×0000FFFF) XOR (x >> 16);

它很完美地满足“好的散列函数”的两个附加条件。

2、哈希冲突(Hash collision)

也就是两个不同输入产生了相同输出值的情况。首先,哈希冲突是无法避免的,因此,哈希算法的选择直接决定了哈希冲突发送的概率;同时必须要对哈希冲突进行处理,方法主要有以下几种:

1, 链地址法

链地址法:对Hash表中每个Hash值建立一个冲突表,即将冲突的几个记录以表的形式存储在其中

2, 开放地址法
下面就来看看每种方法的具体实现吧:

链地址法:

举例说明: 设有 8 个元素 { a,b,c,d,e,f,g,h } ,采用某种哈希函数得到的地址分别为: {0 , 2 , 4 , 1 , 0 , 8 , 7 , 2} ,当哈希表长度为 10 时,采用链地址法解决冲突的哈希表代码如下所示。 
————————————————

3、链地址法代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct _node{
    char *key;
    char *value;
    struct _node *next;
}node;
#define HASHSIZE 101
static node* hashtab[HASHSIZE];
void inithashtab(){
    for(int i=0;i<HASHSIZE;i++){
        hashtab[i]=NULL;
    }
}

unsigned int hash(char *s){
    unsigned int h=0;
    while(*s!='\0'){
        h=*s+h*31;
        s++;
        printf("%d\n",h);
    }
    return h%HASHSIZE;
}
node* lookup(char *n){
    unsigned int id=hash(n);
    node *node=hashtab[id];
    while(node!=NULL){
        if(strcmp(n,node->key)==0){
            return node;
        }
        node=node->next;
    }
    return NULL;
}
char* m_strdup(char *s){
    char *m=malloc(strlen(s)+1);
    if(m==NULL)return NULL;
    strcpy(m,s);
    return m;

}
char* get(char* name){
    if(lookup(name)!=NULL){
        node*n=lookup(name);
        return n->value;
    }else return NULL;
}
int add(char* key,char* value){
    node *n;

    if((n=lookup(key))!=NULL){
        free(n->value);
    }else{
        int id=hash(key);
        n=malloc(sizeof(*n));
        if(n==NULL)return 0;
        n->key=m_strdup(key);
        if(n->key==NULL)return 0;
        n->next=hashtab[id];
        hashtab[id]=n;

    }
    n->value=m_strdup(value);
    if(n->value==NULL)return 0;
    return 1;
}
void displaytable(){
    node *np;
    for(int i=0;i<HASHSIZE;i++){
        if(hashtab[i]==NULL)continue;
        else{
            printf("(");
            np=hashtab[i];
            for(;np!=NULL;np=np->next)
            printf("(%s , %s)",np->key,np->value);
            printf(")\n");
        }
    }

}
void cleanup(){
    node *cur,*pre;
    for(int i=0;i<HASHSIZE;i++){
        if(hashtab[i]==NULL)continue;
        else{
           cur=hashtab[i];
           while(cur){
               pre=cur->next;
               free(cur->key);
               free(cur->value);
               free(cur);
               cur=pre;
           }
        }
    }
}

int main()
{int i;
    char* names[]={"name","address","phone","k101","k110"};
    char* descs[]={"Sourav","Sinagor","26300788","Value1","Value2"};
    inithashtab();
//增加部分--------------------------打印hash_table_index
    for(i = 0; i < 5; i++)
    {
        unsigned int hi=hash(names[i]);
        printf("%s--hash_table_index=%d\n", names[i], hi);
    }
//---------------------------------------打印hash_table_index
    for(i=0;i<5;i++)
        add(names[i],descs[i]);
    displaytable();
    printf("Done\n");
    printf("If we didnt do anything wrong..""we should see %s\n",get("k110"));
    add("phone","9433120451");
    printf("Again if we go right, we have %s and %s\n",get("k101"),get("phone"));
    displaytable();
    cleanup();

    return 0;

}

4、链地址法 hash表实战:1418. 点菜展示表

1418. 点菜展示表

菜名一定是作为key,num数量作为值。查找菜名,找到了加1 。

table *tab[MAXTABLE];  每个桌维护一个hash
foodhash* lookup(char* foodname, int tabid) {
    unsigned int hi = hash(foodname);
    foodhash* f = tab[tabid]->food[hi];
    for (; f != NULL; f = f->next) {
        if (strcmp(f->name, foodname) == 0)
            return f;
    }
    return NULL;
}
/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */

#define MAXFOODNUM 1000
#define MAXTABLE 502
typedef struct _foodhash {
    char* name;
    int num;
    struct _foodhash* next;
}foodhash;
typedef struct _table {
    foodhash* food[MAXFOODNUM];
}table;
table *tab[MAXTABLE];

void initTable() {
    for (int i = 0; i < 502; i++) {
        tab[i] = NULL;
    }
}
int s2i(char* s) {
    int ret = 0;
    while((*s)!=0){
        ret = ret * 10;
        ret = ret + *s - '0';
        s++;
    }
    return ret;
}
char* i2s(int i) {
    char* ret = malloc(10000);
    int len = 0;
    for (; i != 0; i = i / 10) {
        ret[len++] = i % 10 + '0';
    }
    int j = len - 1;
    for (int i = 0; i < j; i++) {
        char temp = ret[i];
        ret[i] = ret[j];
        ret[j] = temp;
        j--;
    }
    ret[len] = '\0';
    return ret;
}
char* m_strdup(char* s) {
    char* m = malloc(strlen(s) + 1);
    if (m == NULL)return NULL;
    strcpy(m, s);
    return m;

}
unsigned int hash(char* s) {
    unsigned int h = 0;
    while (*s != '\0') {
        h = *s + h * 31;
        s++;
    }
    return h % MAXFOODNUM;
}
foodhash* lookup(char* foodname, int tabid) {
    unsigned int hi = hash(foodname);
    foodhash* f = tab[tabid]->food[hi];
    for (; f != NULL; f = f->next) {
        if (strcmp(f->name, foodname) == 0)
            return f;
    }
    return NULL;
}
int add(char* foodname, int num, int tabid) {
    unsigned int hi = hash(foodname);
    foodhash* f = malloc(sizeof(*f));
    if (f == NULL)return 0;
    f->num = num;
    f->name = m_strdup(foodname);
    if (f->name == NULL)return 0;
    f->next = tab[tabid]->food[hi];
    tab[tabid]->food[hi] = f;
    return 1;
}
void clear() {
    for (int i = 0; i < 502; i++) {
        if (tab[i] != NULL) {
            for (int j = 0; j < MAXFOODNUM; j++) {
                if (tab[i]->food[j] != NULL) {
                    foodhash* fd = tab[i]->food[j];
                    foodhash* t;
                    while (fd != NULL) {
                        t = fd->next;
                        free(fd->name);
                        free(fd);
                        fd = t;
                    }
                }
            }
            free(tab[i]);
        }
    }
}
char *** displayTable(char *** orders, int ordersSize, int* ordersColSize, int* returnSize, int** returnColumnSizes){
    initTable();
    tab[501] = malloc(sizeof(table));
    for (int k = 0; k < MAXFOODNUM; k++)
        tab[501]->food[k] = NULL;
    for (int i = 0; i < ordersSize; i++) {
        int tabid = s2i(orders[i][1]);
        if (lookup(orders[i][2], 501) == NULL)
        add(orders[i][2], 1, 501);
        if (tab[tabid] == NULL) {
            tab[tabid] = malloc(sizeof(table));
            for (int k = 0; k < MAXFOODNUM; k++)
                tab[tabid]->food[k] = NULL;
            add(orders[i][2], 1, tabid);
        }
        else {
            foodhash* fd;
            if ((fd = lookup(orders[i][2], tabid)) != NULL) {
                fd->num++;
            }
            else {
                add(orders[i][2], 1, tabid);
            }
        }
    }
    char*** ret = (char***)malloc(sizeof(char**) * 501);

    ret[0] = (char**)malloc(sizeof(char*) * MAXFOODNUM);
    for (int i = 0; i < MAXFOODNUM; i++) {
        ret[0][i] = malloc(21);
    }
    ret[0][0] = "Table";
    int line1 = 1;
    for (int i = 0; i < MAXFOODNUM; i++) {
        if (tab[501]->food[i] != NULL) {
            foodhash* tmp = tab[501]->food[i];
            while (tmp != NULL) {
                ret[0][line1++] = m_strdup(tmp->name);
                tmp = tmp->next;
            }
        }
    }
    for (int i = 1; i < line1-1; i++) {
        for (int j = i+1; j < line1; j++) {
            if (strcmp(ret[0][i], ret[0][j]) > 0)
            {
                char tmp[20];
                strcpy(tmp, ret[0][i]);
                ret[0][i] = malloc(20);
                strcpy(ret[0][i], ret[0][j]);
                ret[0][j] = malloc(20);
                strcpy(ret[0][j], tmp);
            }else continue;
        }
    }
    *returnSize = 1;
    *returnColumnSizes = malloc(sizeof(int) * (501));
    for (int j = 0; j < MAXTABLE-1; j++) {
        if (tab[j] != NULL) {
            ret[*returnSize] = (char**)malloc(sizeof(char*) * line1);
            ret[*returnSize][0] = malloc(10);
            ret[*returnSize][0] = i2s(j);

            for (int i = 1; i < line1; i++) {
                ret[*returnSize][i] = malloc(10);
                foodhash* fd;
                if ((fd = lookup(ret[0][i], j)) != NULL) {
                    ret[*returnSize][i] = i2s(fd->num);      
                }
                else ret[*returnSize][i] = "0";
            }
            (*returnSize)++;
        }
    }

    for (int i = 0; i < (*returnSize); i++) {
        (*returnColumnSizes)[i] = line1;
    }
    
    return ret;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值