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 }