第十五周项目1—哈希表及其运算实现

本文介绍了一个基于线性探测解决冲突的哈希表实现案例。通过具体代码演示了如何构建哈希表、查找特定元素及删除指定项的过程。文章还展示了运行结果,包括哈希表的状态变化和操作后的统计数据。

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

/* 
* Copyright (c)2016,烟台大学计算机与控制工程学院 
* All rights reserved. 
* 文件名称:项目1.cbp 
* 作      者:田艺 
* 完成日期:2016年12月8日 
* 版 本 号:v1.0 
 
* 问题描述:认真阅读并验证哈希表实施查找的相关算法,写程序建立序列{16, 74, 60, 43, 54, 90, 46, 31, 29, 88, 77} 
            的哈希表,装填因子定为0.8,哈希函数为h(k)=key%p,p=11,采用线性探查法解决冲突。测试中:  
             
            (1)输出建立的哈希表;  
            (2)完成关键字为29的元素的查找;  
            (3)在上述哈希表中删除关键字为77的元素,再显示哈希表。 
 
* 输入描述:无 
* 程序输出:测试数据 
*/  

#include <stdio.h>  
#define MaxSize 100         //定义最大哈希表长度  
#define NULLKEY -1          //定义空关键字值  
#define DELKEY  -2          //定义被删关键字值  
typedef int KeyType;        //关键字类型  
typedef char * InfoType;    //其他数据类型  
typedef struct  
{  
    KeyType key;            //关键字域  
    InfoType data;          //其他数据域  
    int count;          //探查次数域  
} HashData;  
  
typedef HashData HashTable[MaxSize];        //哈希表类型  
  
void InsertHT(HashTable ha,int &n,KeyType k,int p)  //将关键字k插入到哈希表中  
{  
    int i,adr;  
    adr=k % p;  
    if (ha[adr].key==NULLKEY || ha[adr].key==DELKEY)    //x[j]可以直接放在哈希表中  
    {  
        ha[adr].key=k;  
        ha[adr].count=1;  
    }  
    else                    //发生冲突时采用线性探查法解决冲突  
    {  
        i=1;                //i记录x[j]发生冲突的次数  
        do  
        {  
            adr=(adr+1) % p;  
            i++;  
        }  
        while (ha[adr].key!=NULLKEY && ha[adr].key!=DELKEY);  
        ha[adr].key=k;  
        ha[adr].count=i;  
    }  
    n++;  
}  
void CreateHT(HashTable ha,KeyType x[],int n,int m,int p)  //创建哈希表  
{  
    int i,n1=0;  
    for (i=0; i<m; i++)         //哈希表置初值  
    {  
        ha[i].key=NULLKEY;  
        ha[i].count=0;  
    }  
    for (i=0; i<n; i++)  
        InsertHT(ha,n1,x[i],p);  
}  
int SearchHT(HashTable ha,int p,KeyType k)      //在哈希表中查找关键字k  
{  
    int i=0,adr;  
    adr=k % p;  
    while (ha[adr].key!=NULLKEY && ha[adr].key!=k)  
    {  
        i++;                //采用线性探查法找下一个地址  
        adr=(adr+1) % p;  
    }  
    if (ha[adr].key==k)     //查找成功  
        return adr;  
    else                    //查找失败  
        return -1;  
}  
int DeleteHT(HashTable ha,int p,int k,int &n)   //删除哈希表中关键字k  
{  
    int adr;  
    adr=SearchHT(ha,p,k);  
    if (adr!=-1)        //在哈希表中找到该关键字  
    {  
        ha[adr].key=DELKEY;  
        n--;            //哈希表长度减1  
        return 1;  
    }  
    else                //在哈希表中未找到该关键字  
        return 0;  
}  
void DispHT(HashTable ha,int n,int m)    //输出哈希表  
{  
    float avg=0;  
    int i;  
    printf(" 哈希表地址:\t");  
    for (i=0; i<m; i++)  
        printf(" %3d",i);  
    printf(" \n");  
    printf(" 哈希表关键字:\t");  
    for (i=0; i<m; i++)  
        if (ha[i].key==NULLKEY || ha[i].key==DELKEY)  
            printf("    ");         //输出3个空格  
        else  
            printf(" %3d",ha[i].key);  
    printf(" \n");  
    printf(" 搜索次数:\t");  
    for (i=0; i<m; i++)  
        if (ha[i].key==NULLKEY || ha[i].key==DELKEY)  
            printf("    ");         //输出3个空格  
        else  
            printf(" %3d",ha[i].count);  
    printf(" \n");  
    for (i=0; i<m; i++)  
        if (ha[i].key!=NULLKEY && ha[i].key!=DELKEY)  
            avg=avg+ha[i].count;  
    avg=avg/n;  
    printf(" 平均搜索长度ASL(%d)=%g\n",n,avg);  
}  
int main()  
{  
    int x[]= {16,74,60,43,54,90,46,31,29,88,77};  
    int n=11,m=13,p=13,i,k=29;  
    HashTable ha;  
    CreateHT(ha,x,n,m,p);  
    printf("\n");  
    DispHT(ha,n,m);  
    i=SearchHT(ha,p,k);  
    if (i!=-1)  
        printf(" ha[%d].key=%d\n",i,k);  
    else  
        printf(" 未找到%d\n",k);  
    k=77;  
    printf(" 删除关键字%d\n",k);  
    DeleteHT(ha,p,k,n);  
    DispHT(ha,n,m);  
    i=SearchHT(ha,p,k);  
    if (i!=-1)  
        printf(" ha[%d].key=%d\n",i,k);  
    else  
        printf(" 未找到%d\n",k);  
    printf(" 插入关键字%d\n",k);  
    InsertHT(ha,n,k,p);  
    DispHT(ha,n,m);  
    printf("\n");  
    return 0;  
}  

运行结果:


### 哈希表平均查找长度概念 哈希表是一种通过哈希函数将键映射到固定范围内的数组索引的数据结构。当多个键被映射到同一个索引时会发生冲突,解决这些冲突的方法有很多种,比如线性探测再散列法、二次探测法等。 对于哈希表而言,平均查找长度(Average Search Length, ASL)分为两种情况: - **查找成功**:指在哈希表中找到给定的关键字所需的比较次数的期望值。 - **查找失败**:指确定某个关键字不在哈希表内所需的最大比较次数的期望值。 这两种情况下ASL的具体定义如下[^1]: #### 查找成功的平均查找长度 (ASLs) \[ \text{ASL}_{\text{s}}=\frac{\sum_{i=1}^{n}\left(\text{第 } i \text{ 个元素的实际查找长度}\right)}{n} \] 其中 \( n \) 是哈希表中存在的有效记录数量。 #### 查找失败的平均查找长度 (ASLf) \[ \text{ASL}_{\text{f}}=\frac{\sum_{j=0}^{m-n-1}\left(\text{未命中位置 } j \text{ 的实际查找长度}\right)}{m-n} \] 这里 \( m \) 表示哈希表总容量;\( n \) 同样表示已有记录数目;分母部分代表所有可能为空的位置总数。 ### 实际案例分析 考虑给出的例子,使用线性探测再散列法处理冲突来构建哈希表,并假设哈希表大小为15 (\(m=15\)),则可以按照上述公式计算不同情形下的ASL。 具体来说,在这个例子中有两个重要参数需要关注: - 关键字集合 {19, 14, 23, 1, 68, 20, 84, 27, 55, 11, 10, 79} - 哈希函数 H(key)=key MOD 13 为了简化说明过程,下面仅展示如何计算查找失败的情况。 由于模运算的结果是从0到12之间的整数值,因此即使哈希表长度设定为15,实际上只有13个不同的槽位可供分配。这意味着存在两处空闲空间用于存储新加入但发生碰撞后的项。 现在尝试向不存在于当前列表中的随机数执行查找操作,直到遇到第一个可用插槽为止所经历的距离即为此类查询的成本。重复此过程覆盖整个剩余区间并累加得到最终结果。 例如,如果要测试数字`X`是否存在于该哈希表中,则会依次检查 `H(X)` 及其后续相邻单元格直至发现匹配项或空白区域。此时统计路径上经过了多少步即可得知单次失败查找对应的代价。 最后汇总所有潜在缺失条目的探查距离并将它们相加以获得总的失败成本,除以理论上的最大可选位置数得出平均值作为查找失败时的ASL。 ```python def calculate_asl_fails(keys, table_size, hash_func): occupied_slots = set() # Fill the slots with given keys using linear probing. for key in keys: index = hash_func(key) while True: if index not in occupied_slots or len(occupied_slots) >= table_size: break index = (index + 1) % table_size occupied_slots.add(index) fail_distances_sum = 0 # Calculate distances to first empty slot from each unoccupied position. for pos in range(table_size): distance = 0 current_pos = pos while current_pos in occupied_slots and distance < table_size: distance += 1 current_pos = (current_pos + 1) % table_size if distance != table_size: # Avoid counting full circle as a failure path. fail_distances_sum += distance num_unfilled_positions = table_size - len(occupied_slots) asl_failures = fail_distances_sum / max(num_unfilled_positions, 1) return asl_failures keys_example = [19, 14, 23, 1, 68, 20, 84, 27, 55, 11, 10, 79] table_length = 15 hash_function = lambda k : k % 13 print(f"Failure Average Search Length is approximately {calculate_asl_fails(keys_example, table_length, hash_function):.2f}") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值