哈希表

1.我们在网站上注册账号时,当填好用户名后,系统都会判断用户名是否已被使用,如果已被使用,系统就会提示该用户名已被注册。系统是如何检测用户名是否被使用的?

可以用哈希表来解决这个问题。哈希表又叫散列表,关键值通过哈希函数映射到数组上,查找时通过关键值直接访问数组。在上面的例子里,我们将用户名通过哈希函数映射成一个整数,也就是数组的存储位置,在检测时用同样方法计算出存储位置,如果位置上已有元素则表示用户名已经被注册。

哈希函数指的是关键值和存储位置建立的对应关系,查找时只要根据这个关系就能找到目标位置。一般我们只要通过一次查找就能找到目标位置,但有些关键字需要多次比较和查找才能找到,这是为什么呢?因为哈希表里,可能存在关键字不同但是哈希地址相同的情况,也就是冲突。一般情况下,冲突是不可避免的,因为关键字集合往往比哈希地址集合大很多。

提高哈希表的查找效率,关键在与哈希函数的构造和解决冲突的方法。哈希函数的构造方法有很多种,我们应该如何构造优秀的哈希函数来减少冲突呢?如果发生了冲突,我们该如何处理冲突,减少比较次数提高查找效率呢?

2.性质

  • 哈希表里的冲突只能减少,是不可避免的
  • 哈希函数构造的好坏会影响查找效率
  • 优秀的处理冲突方法可以减少比较次数,提高查找效率

3.设计哈希函数没有统一的方法,同一个哈希函数不一定能适用所有问题,其产生的影响也是不一样的。哈希函数的设计又是至关重要的,那么我们该如何设计呢?一般来说,设计哈希函数时要达到两个要求:计算简单,计算复杂的哈希函数会增加查询的时间;关键字尽可能地均分到存储地址上,这样可以减少冲突。

4.哈希表的构造,插入,查询,和重建

  1 #include <iostream>
  2 #include <string>
  3 using namespace std;
  4 class HashTable {
  5 private:
  6     string *elem;
  7     int size;
  8 public:
  9     HashTable() {
 10         size = 2000;
 11         elem = new string[size];
 12         for (int i = 0; i < size; i++) {
 13             elem[i] = "#";
 14         }
 15     }
 16     ~HashTable() {
 17         delete[] elem;
 18     }
 19     int hash(string& index) {
 20         int code = 0;
 21         for (size_t i = 0; i < index.length(); i++) {
 22             code = (code * 256 + index[i] + 128) % size;                    //避免负数所以加上128,相加时用的ASCII码的值
 23         }
 24         return code;
 25     }
 26     bool search(string& index, int& pos, int& times) {                      //开放地址法
 27         pos = hash(index);
 28         times = 0;                                                         //记录冲突次数
 29         while (elem[pos] != "#" && elem[pos] != index) {
 30             times++;
 31             if (times < size) {
 32                 pos = (pos + 1) % size;
 33             } else {
 34                 return false;
 35             }
 36         }
 37         if (elem[pos] == index) {
 38             return true;
 39         } else {
 40             return false;
 41         }
 42     }
 43     int insert(string& index) {
 44         int pos, times;
 45         if (search(index, pos, times)) {
 46             return 2;
 47         } else if (times < size / 2) {
 48             elem[pos] = index;
 49             return 1;
 50         } else {
 51             recreate();
 52             return 0;
 53         }
 54     }
 55     void recreate(){
 56         string *temp_elem;
 57         temp_elem=new string[size];
 58         for(int i=0;i<size;i++){
 59             temp_elem[i]=elem[i];
 60         }
 61         int copy_size=size;
 62         size=size*2;
 63         delete[]elem;
 64         elem=new string[size];
 65         for(int i=0;i<size;i++){
 66             elem[i]="#";
 67         }
 68         for(int i=0;i<copy_size;i++){
 69             if(temp_elem[i]!="#"){
 70                 insert(temp_elem[i]);
 71             }
 72         }
 73         delete[]temp_elem;
 74     }
 75 };
 76 int main() {
 77     HashTable hashtable;
 78     string buffer;
 79     int n;
 80     cin >> n;
 81     for (int i = 1; i <= n; i++) {
 82         cin >> buffer;
 83         int ans = hashtable.insert(buffer);
 84         if (ans == 0) {
 85             cout << "insert failed!" << endl;
 86         } else if (ans == 1) {
 87             cout << "insert success!" << endl;
 88         } else if (ans == 2) {
 89             cout << "It already exists!" << endl;
 90         }
 91     }
 92     int temp_pos, temp_times;
 93     cin >> buffer;
 94     if (hashtable.search(buffer, temp_pos, temp_times)) {
 95         cout << "search success!" << endl;
 96     } else {
 97         cout << "search failed!" << endl;
 98     }
 99     return 0;
100 }

5.应用:忽略大小写筛选用户名

 1 #include <iostream>
 2 #include <string>
 3 #include <cctype>
 4 #include <algorithm>
 5 using namespace std;
 6 class HashTable {
 7 private:
 8     string *elem;
 9     int size;
10 public:
11     HashTable() {
12         size = 300000;
13         elem = new string[size];
14         for (int i = 0; i < size; i++) {
15             elem[i] = "#";
16         }
17     }
18     ~HashTable() {
19         delete[] elem;
20     }
21     int hash(string& index) {
22         int code = 0;
23         for (size_t i = 0; i < index.length(); i++) {
24             code = (code * 256 + index[i] + 128) % size;
25         }
26         return code;
27     }
28     bool search(string& index, int& pos, int& times) {
29         pos = hash(index);
30         times = 0;
31         while (elem[pos] != "#" && elem[pos] != index) {
32             times++;
33             if (times < size) {
34                 pos = (pos + 1) % size;
35             } else {
36                 return false;
37             }
38         }
39         if (elem[pos] == index) {
40             return true;
41         } else {
42             return false;
43         }
44     }
45     int insert(string& index) {
46         int pos, times;
47         if (search(index, pos, times)) {
48             return 2;
49         } else if (times < size / 2) {
50             elem[pos] = index;
51             return 1;
52         } else {
53             recreate();
54             return 0;
55         }
56     }
57     void recreate(){
58         string *temp_elem;
59         temp_elem=new string[size];
60         for(int i=0;i<size;i++){
61             temp_elem[i]=elem[i];
62         }
63         int copy_size=size;
64         size=size*2;
65         delete[]elem;
66         elem=new string[size];
67         for(int i=0;i<size;i++){
68             elem[i]="#";
69         }
70         for(int i=0;i<copy_size;i++){
71             if(temp_elem[i]!="#"){
72                 insert(temp_elem[i]);
73             }
74         }
75         delete[]temp_elem;
76     }
77 };
78 int main() {
79     HashTable hashtable;
80     string buffer;
81     int n;
82     cin >> n;
83     for (int i = 1; i <= n; i++) {
84         cin >> buffer;
85         transform(buffer.begin(),buffer.end(),buffer.begin(),::tolower);  
86         int ans = hashtable.insert(buffer);
87         if (ans == 0) {
88             cout << "No" << endl;
89         } else if (ans == 1) {
90             cout << "No" << endl;
91         } else if (ans == 2) {
92             cout << "Yes" << endl;
93         }
94     }
95     
96     return 0;
97 }

 

posted @ 2016-07-15 18:57  绵绵思远道  阅读(266)  评论(0编辑  收藏  举报