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("\n");
53                     break;
54                 }
55             }
56         }
57     }
58     return 0;
59 }

 

posted @ 2013-12-01 11:14  yiyi_xuechen  Views(323)  Comments(0)    收藏  举报