• 哈希表


    C语言哈希表

    【1】设计数据结构

    (1)哈希表由一个结构体HashTable构成

    (2)结构体HashTable由两个元素组成。其一为指针数组(链式存储元素);其二为整型变量(记录元素个数)

    (3)指针数组类型为HashNode *(哈希节点指针)

    (4)结构体HashNode由数据域和指针域组成。数据域也是一种结构类型变量,指针域为一个同类型指针,为了实现链式存储。

    (5)数据域结构体ElemType由关键码以及其他相关信息组成(在此程序里没有添加)

    (6)拟定哈希表长度为13

    【2】C语言表示数据结构

     1 #define   M   13   
     2 typedef  int  KeyType;
     3 typedef  struct 
     4 {
     5     KeyType key;   
     6     //otherinfo;
     7 }ElemType;
     8 typedef struct  _Node
     9 {
    10     ElemType  data;     
    11     _Node     *next;    
    12 }HashNode;
    13 typedef struct
    14 {
    15     HashNode  *table[M];    
    16     int  len;                
    17 }HashTable;

    【3】函数设计

        在设计函数之前,让我们先理解一下基本的逻辑:

        哈希表中存储的每个元素都有一个关键码,而每个关键码都可以通过与哈希表的总数取模(当然这个算法可以任意选择)得到一个索引,而索引就是该元素欲存入的“桶”标识。一个循环链表可以形象的理解为一只桶。

        插入函数采用的前插入方式,删除函数就相当于链表的删除操作,关键仅仅在于对指针操作。

        哈希函数可以有多种实现算法,在此采用取模法。

     (1)哈希函数Hash,取模定位。实现代码如下:

    1 //hash函数
    2 int Hash(KeyType k)
    3 {
    4     return (k % M);
    5 }

     (2)初始化哈希表。元素分别置为空。实现代码如下:

    1 void InitHash(HashTable &ht)
    2 {
    3     ht.len=0;
    4     for(int i=0;i<M;++i)
    5     {
    6         ht.table[i]=NULL;     //置空
    7     }
    8 }

     (3)插入元素InsertHashTable(HashTable &ht,ElemType  x)。引用传入哈希表对象,传入关键字。实现代码如下:

     1 /*
     2 *插入函数
     3 */
     4 void InsertHashTable(HashTable &ht,ElemType x)
     5 {
     6     //判断是否存在
     7     int pos=SearchHash(ht,x);
     8     if(pos == -1)
     9     {
    10         cout<<"已存在"<<endl;
    11         return ;
    12     }
    13     //不存在的前提下:new一个新的节点
    14     HashNode *s=new HashNode();
    15     s->data=x;             
    16     //头部插入法
    17     s->next =ht.table[pos];  
    18     ht.table[pos]=s;
    19     //重置长度                 
    20     ht.len+=1;
    21 }

     (4)在插入之前,我们先要确定关键字映射的索引。函数SearchHash实现这个需求。实现代码如下:

     1 //查询关键码的pos
     2 int SearchHash(HashTable &ht,ElemType x)
     3 {
     4     /*
     5     *初始化
     6     */
     7     //首先定位
     8     int pos=Hash(x.key);
     9     HashNode *p=ht.table[pos];
    10     /*
    11     *循环遍历节点
    12     */
    13     while(p != NULL && p->data.key != x.key)
    14     {
    15         p=p->next;
    16     }
    17     /*
    18     *处理结果
    19     */
    20     //没找到
    21     if(p == NULL)
    22     {
    23         return pos;
    24     }
    25     //找到
    26     else
    27     {
    28         return -1;
    29     }
    30 }

    (5)在实现了添加元素之后,我们相应地考虑到删除元素。删除元素的前提是要找到元素所被存储的节点。于此函数Search实现该功能。返回欲删除元素的指针。实现代码如下:

     1 HashNode *Search(HashTable &ht,ElemType x)
     2 {
     3     /*
     4     *初始化
     5     */
     6     //定位
     7     int pos=Hash(x.key);
     8     HashNode *p=ht.table[pos];
     9     /*
    10     *循环
    11     */
    12     while(p != NULL && p->data.key !=x.key)
    13     {
    14         p=p->next;
    15     }
    16     /*
    17     *结果处理
    18     */
    19     return p;
    20 }

     (6)删除函数RemoveHash(HashTable &ht,ElemType x)设计思想:

        A.调用Hash函数确定元素的索引

        B.依据索引定位元素链表的起点(即就是确定从那个指针数组索引进行遍历)

        C.备用指针

        D.循环遍历

        E.结果处理。具体实现代码如下:

     1 void RemoveHash(HashTable &ht,ElemType x)
     2 {
     3     /*
     4     *初始化
     5     */
     6     int pos=Hash(x.key);
     7     HashNode *q=ht.table[pos];
     8     HashNode *p=NULL;       //备用指针
     9     /*
    10     *循环遍历
    11     */
    12     while(q != NULL && q->data.key != x.key)
    13     {
    14         p=q;
    15         q=q->next;
    16     }
    17     /*
    18     *结果处理
    19     */
    20     //找到的是第一个结点
    21     if(p == NULL && q != NULL)
    22     {
    23         ht.table[pos]=q->next;
    24         ht.len-=1;
    25         delete q;
    26     }
    27     //找到的是其他节点包括最后一个
    28     if(p != NULL && q != NULL)
    29     {
    30         p->next=q->next;
    31         ht.len-=1;
    32         delete q;
    33     }
    34 
    35 }

    【4】测试程序以及源程序代码

      1 #include <iostream>
      2 #include <malloc.h>
      3 using namespace std;
      4 
      5 //数据结构
      6 #define   M   13        //hash表的大小
      7 typedef  int  KeyType;  //关键字类型定义
      8 
      9 //储存元素类型(结构体代表数据库的一行(即就是一个完整的个体))
     10 typedef  struct 
     11 {
     12     KeyType key;   //关键码类型:一般比如学号,身份证号
     13      //otherinfo;
     14 } ElemType;
     15 
     16 //链表节点类型
     17 typedef struct  _Node
     18 {
     19     ElemType  data;      //元素变量
     20     _Node*    next;      //指向下一个的指针
     21 } HashNode;
     22 
     23 //hash表结构
     24 typedef struct
     25 {
     26     HashNode* table[M];    //节点指针(相当于链表头结点)
     27     int  len;              //大小
     28 } HashTable;
     29 
     30 /*
     31 *初始化hash
     32 */
     33 void InitHash(HashTable &ht)
     34 {
     35     ht.len = 0;
     36     for (int i = 0; i < M; ++i)
     37     {
     38         ht.table[i] = NULL;     //置空
     39     }
     40 }
     41 
     42 //hash函数
     43 int Hash(KeyType k)
     44 {
     45     return (k % M);
     46 }
     47 
     48 //查询关键码的pos是否存在
     49 int SearchHash(HashTable &ht, ElemType x)
     50 {
     51     /*
     52     *初始化
     53     */
     54     //首先定位
     55     int pos = Hash(x.key);
     56     HashNode *p = ht.table[pos];
     57     /*
     58     *循环遍历节点
     59     */
     60     while (p != NULL && p->data.key != x.key)
     61     {
     62         p = p->next;
     63     }
     64     /*
     65     *处理结果
     66     */
     67     //没找到
     68     if (NULL == p)
     69         return pos;
     70 
     71    return -1;
     72 }
     73 /*
     74 *插入函数
     75 */
     76 void InsertHashTable(HashTable &ht, ElemType x)
     77 {
     78     //判断是否存在
     79     int pos = SearchHash(ht, x);
     80     if (-1 == pos)
     81     {
     82         cout << "已存在" << endl;
     83         return;
     84     }
     85     //不存在的前提下:new一个新的节点
     86     HashNode *s = new HashNode();
     87     s->data = x;             
     88     //头部插入法
     89     s->next = ht.table[pos];  
     90     ht.table[pos] = s;
     91     //重置长度                 
     92     ht.len += 1;
     93 }
     94 /*
     95 *查询某元素的指针
     96 */
     97 HashNode *Search(HashTable &ht, ElemType x)
     98 {
     99     /*
    100     *初始化
    101     */
    102     //定位
    103     int pos = Hash(x.key);
    104     HashNode *p = ht.table[pos];
    105     /*
    106     *循环
    107     */
    108     while (p != NULL && p->data.key != x.key)
    109     {
    110         p = p->next;
    111     }
    112     /*
    113     *结果处理
    114     */
    115     return p;
    116 }
    117 /*
    118 *删除元素
    119 */
    120 void RemoveHash(HashTable &ht, ElemType x)
    121 {
    122     /*
    123     *初始化
    124     */
    125     int pos = Hash(x.key);
    126     HashNode *q = ht.table[pos];
    127     HashNode *p = NULL;       //备用指针
    128     /*
    129     *循环遍历
    130     */
    131     while (q != NULL && q->data.key != x.key)
    132     {
    133         p = q;
    134         q = q->next;
    135     }
    136     /*
    137     *结果处理
    138     */
    139     //找到的是第一个结点
    140     if (NULL == p && q != NULL)
    141     {
    142         ht.table[pos] = q->next;
    143         ht.len -= 1;
    144         delete q;
    145     }
    146     //找到的是其他节点包括最后一个
    147     if (p != NULL && q != NULL)
    148     {
    149         p->next = q->next;
    150         ht.len -= 1;
    151         delete q;
    152     }
    153 }
    154 
    155 void main()
    156 {
    157     cout << __FILE__ << endl;
    158     cout << __LINE__ << endl;
    159     cout << __TIME__ << endl;
    160 
    161     ElemType ar[11] = {1, 14, 27, 12, 40, 34, 53, 65, 78, 9, 5,};
    162     HashNode *p = NULL;
    163     ElemType x;
    164     HashTable ht;
    165 
    166     InitHash(ht);
    167     for (int i = 0; i < 11; ++i)
    168     {
    169         InsertHashTable(ht, ar[i]);
    170     }
    171     cout << "请输入查找关键码并以-1结束" << endl;
    172     while (cin>>x.key, x.key != -1)
    173     {
    174         p = Search(ht, x);
    175         if (NULL == p)
    176         {
    177             cout << "无此数据" << endl;
    178         }
    179         else
    180         {
    181             cout << "关键码地址:"<< p << "  " << "关键码值:" << p->data.key << endl;
    182         }
    183     }
    184     cout <<"请输入删除的关键码" <<endl;
    185     while (cin>>x.key, x.key != -1)
    186     {
    187         RemoveHash(ht, x);
    188     }
    189 }

    【5】Demo总结

    完成一个简单的程序之前,首先整理思路,把基本的逻辑思路想清楚,再开始一步一步地策划,一点一点的处理相应的功能需求,一次一次的重审自己的设计思路。

    在所有的步骤大概都设计好以后,着手书写代码,实现相应地模块,或者说函数,进而完成整个程序。

    最后测试自己的代码,是否达到了预期地要求,是否可以扩充,有没有多余的代码等。

    本次程序学到了循环链表的基本操作以及哈希表的原理。

     

    Good Good Study, Day Day Up.

    顺序  选择  循环  坚持

    作者:kaizen
    声明:本文版权归作者和博客园共有,欢迎转载。但未经作者同意必须保留此声明,且在文章明显位置给出本文链接,否则保留追究法律责任的权利。
    签名:顺序 选择 循环
  • 相关阅读:
    共享库的使用(.so)文件
    C/C++ 的宏中#和##的作用和展开
    有趣的打字训练
    libtool 创建库的工具
    vcpkg-微软开发的VC++打包工具
    Q他中的乱码再理解
    关于头文件和源文件的分别
    std::set 中内部元素有序条件删除的理解
    python 的 字节码 导入使用
    Pychar-20170301快捷键
  • 原文地址:https://www.cnblogs.com/Braveliu/p/2610692.html
Copyright © 2020-2023  润新知