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 }