1 //哈希表查询与插入删除速率非常快速 2 #include<unordered_map> 3 #include<map> 4 #include<iostream> 5 6 using namespace std; 7 template<typename Key,typename Value> 8 class HashTable 9 { 10 private: 11 const static int upperTol = 3; 12 const static int lowerTol = 1; 13 const static int initCapacity = 1; 14 map<Key,Value> **hashtable;//整个表 15 int M;//哈希表数组的大小 16 int size;//表中已有元素个数 17 18 public: 19 //传参构造 20 HashTable(int m) : M((m),size(0) 21 { 22 //this->hashtable = new map<Key,Value>* [M](); 23 this->hashtable = new map<Key,Value>* [M]; 24 for (inti= 0;i < M;i++) 25 { 26 this->hashtable[i] = new map<Key,Value>; 27 } 28 } 29 //默认构造 30 HashTable() { 31 HashTable(initCapacity); 32 } 33 34 //析构函数 35 ~HashTable() { 36 free(M); 37 } 38 39 public: 40 int getSize() { 41 return size; 42 } 43 44 //添加新元素 45 void add(Key key,Value value) 46 {// 拉链法出来的map如果为空,就动态分配一个map,然后进行插入 47 // 如果key不存在就看内存是否存在,不存在,就分配,存在就插入 48 if (hashtable[hashFunc(key)] == NULL || hashtable[hasFunc(key)]->count(key) == 0)//count() 49 { if (hashtable[hashFunc(key)] == NULL) 50 hashtable[hashFunc(key)] = new map<Key, Value>; 51 hashtable[hashFunc(key)]->insert(make_pair(key, value)); 52 size++; 53 if (size >= maxCapacity()) 54 resize(2 * M); 55 } else { 56 // 否则,修改value. 57 hashtable[hashFunc(key)]->erase(key); 58 hashtable[hashFunc(key)]->insert(make_pair(key, value)); 59 } 60 } 61 /** 62 * 移除Key 63 * @param key 64 * @return 0 success -1 fail 65 */ 66 Value remove(Key key) { 67 Value ret = -1; 68 // 是否包含key,若包含key,则直接删除 69 if (contains(key)) { 70 hashtable[hashFunc(key)]->erase(key); 71 size--; 72 // if (size == 0) delete hashtable[hashFunc(key)]; // 可以添加这行来动态减少内存 73 ret = 0; 74 // initCapacity 保证不会越界 75 if (size < minCapacity() && M / 2 >= initCapacity) resize(M / 2); 76 } 77 return ret; 78 } 79 80 /** 81 * 重设value 82 * @param key 83 * @param value 84 */ 85 void set(Key key, Value value) { 86 // key不存在 87 if (!contains(key)) 88 throw "key not exists!"; 89 // 修改value 90 hashtable[hashFunc(key)]->erase(key); 91 hashtable[hashFunc(key)]->insert(make_pair(key, value)); 92 } 93 /** 94 * 是否包含key 95 * @param key 96 * @return 97 */ 98 bool contains(Key key) { 99 return hashtable[hashFunc(key)] == NULL || this->hashtable[hashFunc(key)]->count(key) == 0 ? false : true; 100 } 101 102 /** 103 * 获取key对应的value 104 * @param key 105 * @return 106 */ 107 108 Value get(Key key) { 109 if (contains(key)) 110 return hashtable[hashFunc(key)]->at(key); 111 return 0; 112 } 113 114 /** 115 * 最大容量 116 * @return 117 */ 118 Value maxCapacity() { 119 return M * upperTol; 120 } 121 122 /** 123 * 最小容量 124 * @return 125 */ 126 Value minCapacity() { 127 return M * lowerTol; 128 } 129 130 private: 131 /** 132 * 哈希函数 133 * @param key 134 * @return 135 */ 136 int hashFunc(Key key) { 137 std::hash<Key> h; 138 return (h(key) & 0x7fffffff) % M; 139 } 140 141 template<typename K, typename V> 142 // 重载<<操作符 143 friend ostream &operator<<(ostream &out, HashTable<K, V> &hashTable); 144 145 /** 146 * 打印hash表中所有数据 147 */ 148 void print() { 149 string res = "{"; 150 for (int i = 0; i < this->M; i++) 151 if (this->hashtable[i]) 152 for (auto m:*(this->hashtable[i])) 153 res += m.first + ":" + to_string(m.second) + ","; 154 res.replace(res.size() - 1, string::npos, "}");//将最后一个字符串替换
//npos是一个静态成员常量值,对于size_t类型的元素,其最大值可能。
该值在字符串成员函数中用作len(或sublen)参数的值时,表示“直到字符串结尾”。 作为返回值,通常用于表示没有匹配项。 该常量定义为值-1,这是因为size_t是无符号整数类型,因此它是此类型可能的最大可表示值。 155 cout << res << endl; 156 } 157 158 /** 159 * 动态调整内存,保证时间复杂度O(1)查找 160 * 把扩容后的操作,平摊到前面每次操作,时间复杂度O(2),那就是O(1)了 161 * @param newM 162 */ 163 void resize(int newM) {
//首先获取新的空间,再将旧的数据复制到新的空间,最后释放旧空间 164 cout << "resize " << newM << endl; 165 map<Key, Value> **newHashTable = new map<Key, Value> *[newM]; 166 for (int i = 0; i < newM; i++) { 167 newHashTable[i] = new map<Key, Value>; 168 } 169 int oldM = M; 170 this->M = newM; 171 for (int i = 0; i < oldM; i++) { 172 map<Key, Value> m = *(hashtable[i]); 173 for (auto p:m) 174 newHashTable[hashFunc(p.first)]->insert(make_pair(p.first, p.second)); 175 } 176 177 178 free(oldM); 179 this->hashtable = newHashTable; 180 } 181 182 private: 183 /** 184 * 释放内存 185 * @param M 186 */ 187 void free(int M) { 188 for (int i = 0; i < M; i++) { 189 if (hashtable[i]) 190 delete hashtable[i]; 191 } 192 delete[]hashtable; 193 } 194 }; 195 196 template<typename K, typename V> 197 ostream &operator<<(ostream &out, HashTable<K, V> &hashTable) { 198 hashTable.print(); 199 return out; 200 } 201 202 /** 203 * 哈希函数的设计原则: 204 * 1.一致性:如果a==b,则hashFunc(a)=o=hashFunc(b) 205 * 2.高效性:计算高效简便 206 * 3.均匀性:哈希值均匀分布 207 */ 208 209 // (hashcode(k1) & 0x7fffffff)%M 210 // f为7个一个f有4个1那么就是28个1,,7有3个1,,总共31个1 211 // 而最高位第32位表示正负,故上述取&后,变为正数。 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 };
哈希表:以map作为底部容器,由装多个map地址的数组和多个map构成。
map:所有元素都唯一,且所有元素自动从小到大排序
1)map::count()----根据键值查看map中是否由此节点
1 #include<iostream> 2 #include<map> 3 int main() 4 { 5 std::map<char,int> mymap; 6 char c; 7 8 mymap['a'] = 101; 9 mymap['b'] = 202; 10 mymap['c'] = 303; 11 12 for (c = 'a';c < 'e';c++) 13 { 14 std::cout << c << endl; 15 if (mymap.count(c) > 0) 16 std::cout <<"is an element "; 17 else 18 std::cout << "is not an element "; 19 } 20 21 }
2)map::insert()---插入节点
1 #include <iostreram> 2 #include <map> 3 4 int main() 5 { 6 sta::map<char,int> mymap; 7 //first version----single parameter 8 mymap.insert(std::pair<char,int>('a',100)); 9 mymap.insert(std::pair<char,int>('z',200)); 10 mymap.insert(std::make_pair('d',321)); 11 12 std::pair<std::map<char,int>::iterator,bool> ret; 13 ret = mymap.insert(std::pair<char,int>('z',500)); 14 if (ret.second == false){ 15 std::cout << "element 'z' already existed"; 16 std::cout << "with a value of " << ret.first->second << estd::endl 17 } 18 //second version---with hint position 19 std::map<char,int>::iterator it = mymap.begin(); 20 mymap.insert(it,std::pair<char,int>('b',300)); 21 mymap.insert(it,std::pair<char,int>)'c',400)); 22 23 //third version----range insertion 24 std::map<char,int> anothermap; 25 anothermap.insert(mymap.begin(),mymap.find('c)); 26 //show contents 27 std::cout << "mymap contains: "; 28 for (it = mymap.begin();it != mymap.end();it++) 29 { 30 std::cout << it->first << "-->" << it->second << ' '; 31 } 32 33 std::cout << "anothermap contains: "; 34 for (it = anothermap.begin();it != aonthermap.end();it++) 35 std::cout << it->first << "-->" << it->second << ' ' ; 36 }
3)string成员函数
(1)replace
1 #include <iostream> 2 3 #include <string> 4 5 int main() 6 7 { 8 9 std::string base = "this is a test string"; 10 11 std::string str2 = "n example"; 12 13 std::string str3 = "sample phrase"; 14 15 std::string str4 = "useful"; 16 17 //versionj1-----use position 18 19 std::string str = base; 20 21 str.replace(9,5,str2); 22 23 str.replace(19,6,str3,7,6); 24 25 str.replace(8,10,"just a"); 26 27 str.replace(8,6,"a shorty",7); 28 29 str.replace(22,1,3,'!'); 30 31 32 33 //using iterator 34 35 str.replace(str.begin(),str.end()-3,str3); 36 37 str.replace(str.begin(),str.begin()+6,"replace"); 38 39 str.replace(str.begin(),str.begin+14,"is"); 40 41 }
(2)string::npos
静态const size_t npos = -1;
size_t的最大值
npos是一个静态成员常量值,对于size_t类型的元素,其最大值可能。
该值在字符串成员函数中用作len(或sublen)参数的值时,表示“直到字符串结尾”。 作为返回值,通常用于表示没有匹配项。 该常量定义为值-1,这是因为size_t是无符号整数类型,因此它是此类型可能的最大可表示值。