• Algorithm Design——Hash表


      1 /**
      2 哈希表的几个概念:
      3 映像:由哈希函数得到的哈希表是一个映像。
      4 冲突:如果两个关键字的哈希函数值相等,这种现象称为冲突。
      5 
      6 处理冲突的几个方法:
      7 1、开放地址法:用开放地址处理冲突就是当冲突发生时,形成一个地址序列,沿着这个序列逐个深测,直到找到一个“空”的开放地址,将发生冲突的关键字值存放到该地址中去。
      8 例如:hash(i)=(hash(key)+d(i)) MOD m (i=1,2,3,......,k(k<m-1)) d为增量函数,d(i)=d1,d2,d3,...,dn-1
      9 根据增量序列的取法不同,可以得到不同的开放地址处理冲突探测方法。
     10 有线性探测法、二次方探测法、伪随机探测法。
     11 2、链地址法:把所有关键字为同义词的记录存储在一个线性链表中,这个链表成为同义词链表,即把具有相同哈希地址的关键字值存放在同义链表中。
     12 3、再哈希表:费时间的一种方法
     13 */
     14 
     15 #include<iostream>  
     16 using namespace std;  
     17 
     18 typedef int KeyType; //设关键字域为整形,需要修改类型时,只需修改这里就可以  
     19 const int NULLKEY=0; //NULLKEY表示该位置无值  
     20 int c=0; //用来统计冲突次数  
     21 
     22 struct Elemtype //数据元素类型  
     23 {  
     24     KeyType key;  
     25     int ord;   
     26 };  
     27 
     28 int hashsize[]={11,19,29,37,47}; //hash表容量递增表  
     29 int Hash_length=0;//hash表表长  
     30 
     31 class HashTable  
     32 {  
     33 private:  
     34     Elemtype *elem; //数据元素数组,动态申请  
     35     int count;// 当前数据元素个数  
     36     int size; //决定hash表的容量为第几个,hashsize[size]为当前hash容量  
     37 public:  
     38 
     39     int Init_HashTable() //构造一个空hash表  
     40     {  
     41         int i;  
     42         count=0;  
     43         size=0; //初始化容量为hashsize[0]=11  
     44         Hash_length=hashsize[0];  
     45         elem=new Elemtype[Hash_length];  
     46         if(!elem)  
     47         {  
     48             cout<<"内存申请失败"<<endl;  
     49             exit(0);  
     50         }  
     51         for(i=0;i<Hash_length;i++)  
     52             elem[i].key=NULLKEY;  
     53         return 1;  
     54     }  
     55 
     56     void Destroy_HashTable()  
     57     {  
     58         delete[]elem;  
     59         elem=NULL;  
     60         count=0;  
     61         size=0;  
     62     }  
     63 
     64     unsigned Hash(KeyType k) //hash函数的一种(取模法)  
     65     {  
     66         return k%Hash_length;  
     67     }  
     68 
     69     void Collision(int &p,int d) //解决冲突  
     70     {  
     71         p=(p+d)%Hash_length; //采用开放地址法里的线性探测  
     72     }  
     73 
     74     bool Search_Hash(KeyType k,int &p) //查找  
     75     {  
     76         //在开放地址hash表中查找关键字等于k的元素  
     77         //若找到用p表示待查数据,查找不成功时,p指向的是可插入地址  
     78         c=0;  
     79         p=Hash(k); //求hash地址  
     80         while(elem[p].key!=NULLKEY && elem[p].key!=k)  
     81         {  
     82             c++;  
     83             if(c<Hash_length)  
     84                 Collision(p,c);  
     85             else  
     86                 return 0; //表示查找不成功  
     87         }  
     88         if(elem[p].key==k)  
     89             return 1;  
     90         else  
     91             return 0;  
     92 
     93     }  
     94 
     95     int Insert_Hash(Elemtype e) //插入  
     96     {  
     97         //在查找不成功的情况下将k插入到hash表中  
     98         int p;  
     99         if(Search_Hash(e.key,p))  
    100             return -1; //表示该元素已在hash表中  
    101         else if(c<hashsize[size]/2) //冲突次数未达到上限  
    102         {  
    103             //插入e  
    104             elem[p]=e;  
    105             count++;  
    106             return 1;  
    107         }  
    108         else  
    109             ReCreate_HashTable(); // 重建hash表  
    110         return 0; //插入失败  
    111     }  
    112 
    113     void ReCreate_HashTable() //重建hash表  
    114     {  
    115         int i,count2=count;  
    116         Elemtype *p,*elem2=new Elemtype[count];  
    117         p=elem2;  
    118         cout<<"____重建hash表_____"<<endl;  
    119         for(i=0;i<Hash_length;i++) //将原有元素暂存到elem2中  
    120             if(elem[i].key!=NULLKEY)  
    121                 *p++=*(elem+i);  
    122         count=0;delete []elem;  
    123         size++; //hash容量增大  
    124         Hash_length=hashsize[size];  
    125         p=new Elemtype[Hash_length];  
    126         if(!p)  
    127         {  
    128             cout<<"空间申请失败"<<endl;  
    129             exit(0);  
    130         }  
    131         elem=p;  
    132         for(i=0;i<Hash_length;i++)  
    133             elem[i].key=NULLKEY;  
    134         for(p=elem2;p<elem2+count2;p++) //将原有元素放回新表  
    135             Insert_Hash(*p);  
    136     }  
    137 
    138     void Traverse_HashTable()  
    139     {  
    140         cout<<"哈希地址0->"<<Hash_length-1<<endl;  
    141         for(int i=0;i<Hash_length;i++)  
    142             if(elem[i].key!=NULLKEY)  
    143                 cout<<"元素的关键字值和它的标志分别是:"<<elem[i].key<<"  "<<elem[i].ord<<endl;  
    144 
    145     }  
    146 
    147     void Get_Data(int p)  
    148     {  
    149         cout<<"元素的关键字值和它的标志分别是:"<<elem[p].key<<"  "<<elem[p].ord<<endl;  
    150     }  
    151 
    152 };  
    153 
    154 int main()  
    155 {  
    156     Elemtype r[12]={{17,1},{60,2},{29,3},{38,4},{1,5},{2,6},{3,7},{4,8},{5,9},{6,10},{7,11},{8,12}};  
    157     HashTable H;  
    158     int i,p,j;  
    159     KeyType k;  
    160     H.Init_HashTable();  
    161     for(i=0;i<11;i++) //插入前11个记录  
    162     {  
    163         j=H.Insert_Hash(r[i]);  
    164         if(j==-1)  
    165             cout<<"表中已有关键字为"<<r[i].key<<"  "<<r[i].ord<<"的记录"<<endl;  
    166     }  
    167 
    168     cout<<"按哈希地址顺序遍历哈希表"<<endl;  
    169     H.Traverse_HashTable();  
    170     cout<<endl;  
    171 
    172     cout<<"输入要查找的记录的关键字:";  
    173     cin>>k;  
    174     j=H.Search_Hash(k,p);  
    175     if(j==1)  
    176         H.Get_Data(p);  
    177     else  
    178         cout<<"无此记录"<<endl;  
    179 
    180     j=H.Insert_Hash(r[11]); //插入最后一个元素  
    181     if(j==0)  
    182     {  
    183         cout<<"插入失败"<<endl;  
    184         cout<<"需要重建哈希表才可以插入"<<endl;  
    185         cout<<"____重建哈希表____"<<endl;  
    186         H.Insert_Hash(r[i]); //重建后重新插入  
    187     }  
    188 
    189     cout<<"遍历重建后的哈希表"<<endl;  
    190     H.Traverse_HashTable();  
    191     cout<<endl;  
    192 
    193     cout<<"输入要查找的记录的关键字:";  
    194     cin>>k;  
    195     j=H.Search_Hash(k,p);  
    196     if(j==1)  
    197         H.Get_Data(p);  
    198     else  
    199         cout<<"该记录不存在"<<endl;  
    200 
    201     cout<<"____销毁哈希表____"<<endl;  
    202     H.Destroy_HashTable();  
    203 
    204     return 0;  
    205 }
     1 /**Hash实例一:
     2 题目描述: 读入N名学生的成绩,将获得某一给定分数的学生人数输出。
     3 
     4 输入:
     5 测试输入包含若干测试用例,每个测试用例的格式为 
     6 第1行:N 
     7 第2行:N名学生的成绩,相邻两数字用一个空格间隔。 
     8 第3行:给定分数 
     9 当读到N=0时输入结束。其中N不超过1000,成绩分数为(包含)0到100
    10 之间的一个整数。 
    11 
    12 输出:
    13 对每个测试用例,将获得给定分数的学生人数输出。
    14 
    15 样例输入: 
    16 3
    17 80 60 90 
    18 60 
    19 2
    20 85 66 
    21 0 
    22 5
    23 60 75 90 55 75 
    24 75 
    25 0
    26 
    27 样例输出: 
    28 1 
    29 0 
    30 2
    31 */
    32 
    33 #include<cstdio>
    34 
    35 int main()
    36 {
    37     int n;
    38     while(scanf_s("%d", &n) != EOF && n != 0)
    39     {
    40         int Hash[101] = {0};//建立一个初始为0的Hash数组用来记录各种分数出现的次数
    41         for(int i = 1 ; i <= n ; i ++)
    42         {
    43             int x;
    44             scanf_s("%d", &x);
    45             Hash[x] ++;//统计分数出现次数
    46         }
    47 
    48         int aim;
    49         scanf_s("%d", &aim);
    50         printf_s("%d", Hash[aim]);//得到目标分数后,只需简单查询我们统计的数量即可
    51     }
    52 }
     1 /**Hash实例二:
     2 题目描述: 给你n个整数,请按从大到小的顺序输出其中前m大的数。
     3 
     4 输入: 
     5 每组测试数据有两行,第一行有两个数n,m(0<n,m<1000000),第二行包含n
     6 个各不相同,且都处于区间[-500000,500000]的整数。
     7 
     8 输出:
     9 对每组测试数据按从大到小的顺序输出前m大的数。
    10 
    11 样例输入: 
    12 5 3
    13 3 -35 92 213 -644 
    14 
    15 样例输出:
    16 213 92 3
    17 */
    18 
    19 #include<cstdio>
    20 
    21 #define OFFSET 500000
    22 
    23 int Hash[1000001];
    24 
    25 int main()
    26 {
    27     int n, m;
    28     while(scanf_s("%d%d", &n, &m) != EOF)
    29     {
    30         for(int i = -500000 ; i <= 500000 ; i ++)
    31         {
    32             Hash[i + OFFSET] = 0;//初始化
    33         }
    34 
    35         for(int i = 1 ; i <= n ; i ++)
    36         {
    37             int x;
    38             scanf_s("%d", &x);
    39             Hash[x + 500000] = 1;//凡是出现过的数字,该数组元素均被设置成1
    40         }
    41 
    42         for(int i = 500000 ; i >= -500000 ; i --)
    43         {
    44             if(Hash[i + OFFSET] == 1)
    45             {
    46                 printf_s("%d", i);
    47                 m --;
    48                 if(m !=0)
    49                     printf_s(" ");
    50                 else
    51                 {
    52                     printf_s("
    ");
    53                     break;
    54                 }
    55             }
    56         }
    57     }
    58     return 0;
    59 }
  • 相关阅读:
    linux 文件类型 文件权限
    微信公众号支付
    struts2 详解
    git 命令行操作
    javascript 闭包
    SVN 基本操作
    javascript 函数 方法
    git
    javascript变量 数组 对象
    Intellij调试debug
  • 原文地址:https://www.cnblogs.com/yiyi-xuechen/p/3452340.html
Copyright © 2020-2023  润新知