• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > 详解散列表算法与其相关的C语言实现

详解散列表算法与其相关的C语言实现

作者:zinss26914 字体:[增加 减小] 来源:互联网 时间:2017-05-28

zinss26914 通过本文主要向大家介绍了c语言算法详解,c语言指针详解,c语言题库及详解答案,c语言关键字详解,c语言链表详解等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

散列表(也叫哈希表)是一种查找算法,与链表、树等算法不同的是,散列表算法在查找时不需要进行一系列和关键字(关键字是数据元素中某个数据项的值,用以标识一个数据元素)的比较操作。

    散列表算法希望能尽量做到不经过任何比较,通过一次存取就能得到所查找的数据元素,因而必须要在数据元素的存储位置和它的关键字(可用key表示)之间建立一个确定的对应关系,使每个关键字和散列表中一个唯一的存储位置相对应。因此在查找时,只要根据这个对应关系找到给定关键字在散列表中的位置即可。这种对应关系被称为散列函数(可用h(key)表示)。

    根据设定的散列函数h(key)和处理冲突的方法将一组关键字key映像到一个有限的连续的地址区间上,并以关键字在地址区间中的像作为数据元素在表中的存储位置,这种表便被称为散列表,这一映像过程称为散列,所得存储位置称为散列地址。

    关键字、散列函数以及散列表的关系如下图所示:

201581193721542.jpg (401×270)

     1、散列函数

    散列函数是从关键字到地址区间的映像。

    好的散列函数能够使得关键字经过散列后得到一个随机的地址,以便使一组关键字的散列地址均匀地分布在整个地址区间中,从而减少冲突。

    常用的构造散列函数的方法有:

    (1)、直接定址法

    取关键字或关键字的某个线性函数值为散列地址,即:

    h(key) = key   或 h(key) = a * key + b

    其中a和b为常数。

    (2)、数字分析法

    (3)、平方取值法

    取关键字平方后的中间几位为散列地址。

    (4)、折叠法

    将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为散列地址。

    (5)、除留余数法

    取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址,即:

    h(key) = key MOD p    p ≤ m

    (6)、随机数法

    选择一个随机函数,取关键字的随机函数值为它的散列地址,即:

    h(key) = random(key)

    其中random为随机函数。

    2、处理冲突

    对不同的关键字可能得到同一散列地址,即key1 ≠ key2,而h(key1)= h(key2),这种现象称为冲突。具有相同函数值的关键字对该散列函数来说称作同义词。

    在一般情况下,散列函数是一个压缩映像,这就不可避免地会产生冲突,因此,在创建散列表时不仅要设定一个好的散列函数,而且还要设定一种处理冲突的方法。

    常用的处理冲突的方法有:

    (1)、开放定址法

    hi =(h(key) + di) MOD m     i =1,2,…,k(k ≤ m-1)

    其中,h(key)为散列函数,m为散列表表长,di为增量序列,可有下列三种取法:

    1)、di = 1,2,3,…,m-1,称线性探测再散列;

    2)、di = 12,-12,22,-22,32,…,±k2 (k ≤m/2),称二次探测再散列;

    3)、di = 伪随机数序列,称伪随机探测再散列。

    (2)、再散列法

    hi = rhi(key)   i = 1,2,…,k

    rhi均是不同的散列函数。

    (3)、链地址法

    将所有关键字为同义词的数据元素存储在同一线性链表中。假设某散列函数产生的散列地址在区间[0,m-1]上,则设立一个指针型向量void *vec[m],其每个分量的初始状态都是空指针。凡散列地址为i的数据元素都插入到头指针为vec[i]的链表中。在链表中的插入位置可以在表头或表尾,也可以在表的中间,以保持同义词在同一线性链表中按关键字有序排列。

    (4)、建立一个公共溢出区


相关的C语言解释

hash.h
哈希表数据结构&&接口定义头文件

 

  #ifndef HASH_H 
  #define HASH_H 
   
  #define HASH_TABLE_INIT_SIZE 7 
   
  #define SUCCESS 1 
  #define FAILED 0 
   
   
  /** 
   * 哈希表槽的数据结构 
   */ 
  typedef struct Bucket { 
    char *key; 
    void *value; 
    struct Bucket *next; 
  } Bucket; 
   
  /** 
   * 哈希表数据结构 
   */ 
  typedef struct HashTable { 
    int size;  // 哈希表大小 
    int elem_num;  // 哈希表已经保存的数据元素个数 
    Bucket **buckets; 
  } HashTable; 
   
  int hashIndex(HashTable *ht, char *key); 
  int hashInit(HashTable *ht); 
  int hashLookup(HashTable *ht, char *key, void **result); 
  int hashInsert(HashTable *ht, char *key, void *value); 
  int hashRemove(HashTable *ht, char *key); 
  int hashDestory(HashTable *ht); 
  #endif 
</div>


hash.c
哈希表操作函数具体实现

  #include <stdio.h> 
  #include <stdlib.h> 
  #include <string.h> 
  #include "hash.h" 
   
  /** 
   * 初始化哈希表 
   * 
   * T = O(1) 
   * 
   */ 
  int hashInit(HashTable *ht) 
  { 
    ht->size = HASH_TABLE_INIT_SIZE; 
    ht->elem_num = 0; 
    ht->buckets = (Bucket **)calloc(ht->size, sizeof(Bucket *)); 
   
    if (ht->buckets == NULL) 
      return FAILED; 
    else 
      return SUCCESS; 
  } 
   
  /** 
   * 散列函数 
   * 
   * T = O(n) 
   * 
   */ 
  int hashIndex(HashTable *ht, char *key) 
  { 
    int hash = 0; 
   
    while (*key != '\0') { 
      hash += (int)*key; 
      key ++; 
    } 
   
    return hash % ht->size; 
  } 
   
  /** 
   * 哈希查找函数 
   * 
   * T = O(n) 
   * 
   */ 
  int hashLookup(HashTable *ht, char *key, void **result) 
  { 
    int index = hashIndex(ht, key); 
   
    Bucket *bucket = ht->buckets[index]; 
   
    while (bucket) { 
      if (strcmp(bucket->key, key) == 0) { 
        *result = bucket->value; 
        return SUCCESS; 
      } 
      bucket = bucket->next; 
    } 
   
    return FAILED; 
  } 
   
   
  /** 
   * 哈希表插入操作 
   * 
   * T = O(1) 
   * 
   */ 
  int hashInsert(HashTable *ht, char *key, void *value) 
  { 
    int index = hashIndex(ht, key); 
   
    Bucket *org_bucket, *tmp_bucket; 
    org_bucket = tmp_bucket = ht->buckets[index]; 
   
    // 检查key是否已经存在于hash表中 
    while (tmp_bucket) { 
      if (strcmp(tmp_bucket->key, key) == 0) { 
        tmp_bucket->value = value; 
        return SUCCESS; 
      } 
      tmp_bucket = tmp_bucket->next; 
    } 
   
    Bucket *new = (Bucket *)malloc(sizeof(Bucket)); 
     
    if (new == NULL)  return FAILED; 
   
    new->key = key; 
    new->value = value; 
    new->next = NULL; 
   
    ht->elem_num += 1; 
   
    // 头插法 
    if (org_bucket) { 
      new->next = org_bucket; 
    } 
   
    ht->buckets[index] = new; 
   
    return SUCCESS;  
  } 
   
  /** 
   * 哈希删除函数 
   * 
   * T = O(n) 
   * 
   */ 
  int hashRemove(HashTable *ht, char *key) 
  { 
    int index = hashIndex(ht, key); 
   
    Bucket *pre, *cur, *post; 
   
    pre = NULL; 
    cur = ht->buckets[index]; 
   
    while (cur) { 
      if (strcmp(cur->key, key) == 0) { 
        post = cur->next; 
         
        if (pre == NULL) { 
          ht->buckets[index] = post; 
        } else { 
          pre->next = post; 
        } 
   
        free(cur); 
   
        return SUCCESS; 
      } 
   
      pre = cur; 
      cur = cur->next; 
    } 
   
    return FAILED; 
  } 
   
  /** 
   * 哈希表销毁函数 
   * 
   * T = O(n) 
   */ 
  int hashDestory(HashTable *ht) 
  { 
    int i; 
    Bucket *cur, *tmp; 
   
    cur = tmp = NULL; 
   
    for (i = 0; i < ht->size; i ++) { 
      cur = ht->buckets[i]; 
   
      while (cur) {



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • C语言 冒泡排序算法详解及实例
  • C语言 选择排序算法详解及实现代码
  • C语言中使用快速排序算法对元素排序的实例详解
  • 详解散列表算法与其相关的C语言实现
  • C语言位图算法详解

相关文章

  • 2017-05-28c语言网络编程-标准步骤(改进版)
  • 2017-05-28C++实现基数排序的方法详解
  • 2017-05-28C++条件语句和条件运算符的使用方法讲解
  • 2017-05-28C++设计模式编程中简单工厂与工厂方法模式的实例对比
  • 2017-05-28基于堆的基本操作的介绍
  • 2017-05-28c++中template对字符串的处理方法
  • 2017-08-17C++构造函数和析构函数的调用顺序
  • 2017-05-28举例讲解C语言链接器的符号解析机制
  • 2022-04-30C语言指针变量的定义和使用(精华)
  • 2017-05-28C++/Php/Python/Shell 程序按行读取文件或者控制台的实现

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • C语言中char*和char[]用法区别分析
    • C++实现数字转换为十六进制字符串的方法
    • c++图像处理:24位真彩图颜色变换实例
    • 解析c++中参数对象与局部对象的析构顺序的详解
    • 新旧MFC版本实现CEdit透明的2种方法的实例代码
    • C语言模拟实现C++的继承与多态示例
    • C语言中进制知识汇总
    • C语言 typedef:给类型起一个别名
    • 基于Windows API实现遍历所有文件并删除的方法
    • 浅谈C++对象的内存分布和虚函数表

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有