C 算法精介----哈希表->链式哈希表->分析与实现

本文介绍了哈希表的基本概念,包括哈希函数、哈希冲突及其处理方法,并详细讲解了一种常用的链式哈希表的实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

   数组的特点是:寻址容易,插入和删除困难;而链表的特点是:寻址困难,插入和删除容易。那么我们能不能综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构?答案是肯定的,这就是我们要提起的哈希表,哈希表有多种不同的实现方法,我接下来解释的是最常用的一种方法(链式哈希表)


[1]hash函数定义 
   根据key,计算出key对应记录的储存位置
   position = f(key)
   函数f就是hash函数

[2]hash冲突定义 
    不同的key可能得到相同的position。原因为key值的范围过大。如int.
如果构造一个完全没有冲突的表。那么对应的地址空间就是4G,这是根本不
实现的。为了处理这个问题。就允许不同的key可以有相同的position。

[3]hash表定义 
   映射的集合

[4]设计一个好的hash函数非常重要 
   由[2]可知,一个好的hash函数可以使positions集中分布在某一段内存地址范围内。
   并且position在这段地址范围内存尽量均匀。这样每个key对应的position就尽可能
  少了,即hash冲突少。查找就会快一点。

[5]所谓的hash桶定义 
   就是预分配的一段连续的储存空间

[6]处理冲突的方法 
 (1)开放定址法:就是先指定一个桶,然后position = f(key,d),如果postion已经存在了,改变参数d,
     继续计算position = f(key,d),直到postion不存在
    d的不同取值的算法有:线性探测再散列,二次探测再散列,伪随机探测再散列。
     听这名字觉得好高深哦。实际上, 就是为了更高效地计算出没有使用的position
 (2)链地址法
     就是把position相同的item按插入的先后顺序组成一个链表

经典的字符串哈希函数

  
/*hashpjw.c*/  
  
unsigned int hashpjw(const void *key)  
{  
    const char *ptr;  
    unsigned int val;  
  
    val = 0;  
    ptr = key;  
    while (*ptr != '\0'){  
        unsigned int tmp;  
        val = (val << 4) +(*ptr);  
        if (tmp = (val & 0xf0000000)){  
            val = val ^ (tmp >> 24);  
            val = val ^ tmp;  
        }  
        ptr++;  
    }  
    return val%PRIME_TBLSIZ //桶的个数  
}  








由上图可以看到 :由数组+链表组成的




链式哈希表定于与实现

//
//  Chtbl.h
//  Algorithms&Data_structures
//
//  Created by TTc on 15-2-3.
//  Copyright (c) 2015年 TTc. All rights reserved.
//

#ifndef __Algorithms_Data_structures__Chtbl__
#define __Algorithms_Data_structures__Chtbl__

#include <stdlib.h>

/*单链表的头文件*/
#include "List.h"

/* 定义一个链式哈希表的结构体*/

typedef struct Chtbl_ {
    int buckets; /*哈希表分配桶的个数*/
    int (*h)(const void *key);/*哈希函数指针h */
    int (*match)(const void *key1,const void *key2);/*判断2个键是否匹配*/
    void (*destroy)(void *data);/*释放内存空间*/
    
    int size;/*成员个数*/
    List *table;/*哈希表中链表桶的头指针*/
}Chtbl;

/* 函数接口*/
int  chtbl_init (Chtbl *htbl,int buckets,int (*h)(const void *key),int
                 (*match)(const void *key1,const void *key2),void (*destroy)(void *data));
int chtbl_destroy (Chtbl *htbl);
int chtbl_insert(Chtbl *htbl,const void *data);
int chtbl_remove (Chtbl *htbl,void **data);
int chtbl_lookup(const Chtbl *htbl,void **data);

#define chtbl_size (Chtbl *htbl) ((htbl)->size)



#endif /* defined(__Algorithms_Data_structures__Chtbl__) */

//
//  Chtbl.c
//  Algorithms&Data_structures
//
//  Created by TTc on 15-2-3.
//  Copyright (c) 2015年 TTc. All rights reserved.
//

#include "Chtbl.h"
#include <stdio.h>
#include <string.h>



/*初始化 哈希表结构体*/
int
chtbl_init(Chtbl *htbl,int buckets,int (*h)(const void *key),
           int (*match)(const void *key1,const void *key2),void (*destroy)(void *data)){
    int i ;
     /* 申请空间为桶(实质是一个单链表)*/
    if((htbl->table = (List*)malloc(buckets * sizeof(List))) == NULL ){
        return -1;
    }
   /*初始化 哈希表*/
    htbl->buckets = buckets;
    for (i=0; i<buckets; i++) {
        list_init(&htbl->table[i], destroy);
    }
    
    htbl->h = h;
    htbl->match = match;
    htbl->destroy = destroy;
    
    htbl->size = 0;
    return 0;
}

int
chtbl_destroy (Chtbl *htbl){
    int i ;
    for (i=0; i < htbl->buckets; i++) {
        list_destroy(&htbl->table[i]);
    }
    free(htbl->table);
    memset(htbl, 0, sizeof(Chtbl));
    return 0;
}

/* 插入数据
 * return 成功返回0;失败返回-1;存在返回1;
 *
 */
int
chtbl_insert(Chtbl *htbl,const void *data){
    void *temp;
    int  bucket;
    int  retval;
    //Do nothing if the data is already in the table
    temp = (void*)data;
    if(chtbl_lookup(htbl, &temp) == 0)
        return 1;
    //Hash  the key
    bucket = htbl->h(data) % htbl->buckets;
    
    //Insery the data into the buckets
    /*插入哈希表*/
    if ((retval = list_ins_next(&htbl->table[bucket], NULL, data)) == 0)
        htbl ->size ++;
    return retval;
}

/*删除数据
 *return 成功返回0;失败返回-1;
 */
int
chtbl_remove (Chtbl *htbl,void **data){
    ListElmt *element, *prev;
    int bucket;
    //Hash  the key
    /*获得哈希键*/
    bucket = htbl->h(*data) % htbl->buckets;
    //search  for  the data  in the bucket .
    prev = NULL;
     /*查找在哈希表中的data*/
    for (element = list_head(&htbl->table[bucket]); element != NULL; element = list_next(element)) {
        
        if(htbl->match(*data,list_data(element))){
            //Remove the data from the bucket
            if(list_rem_next(&htbl->table[bucket], prev, list_data(element)) == 0){
                
                htbl->size --;
                return 0;
            }  else {
                return -1;
            }
        }
        prev = element;
    }
    //returen  that the data was not found.
    return -1;
}

/* 在哈希表中查找元素
 *return :如果找到元素返回0;否则返回-1.
 */
int
chtbl_lookup(const Chtbl *htbl,void **data){
    ListElmt *element;
    int bucket;
    //Hash  the key
    bucket = htbl->h(*data) % htbl->buckets;
    //search  for  the data  in the bucket .
    for (element = list_head(&htbl->table[bucket]); element != NULL; element = list_next(element)) {
        if(htbl->match(*data,list_data(element))){
            //Pass back the data from the table
            *data = list_data(element);
            return 0;
        }
    }
    //returen  that the data was not found.
    return -1;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值