自定義hash鍵C++
阿新 • • 發佈:2018-06-17
rec htm 自己的 ring 獲得 spa 容器 唯一值 insert
參考:https://stackoverflow.com/questions/17016175/c-unordered-map-using-a-custom-class-type-as-the-key
http://zh.cppreference.com/w/cpp/container/unordered_map/unordered_map
https://www.cnblogs.com/chixinfushui/p/9019988.html
關於寫背包問題的程序,遇到需要自定義鍵值的情況。
寫的程序自定義鍵值需要包含背包容量weight以及目前物品個數number兩個值,對應的鍵值則是目前背包容量以及物品個數下得到的最大價值value,即目前條件下的最優解。
用c++的unordered_map存儲自定義鍵值對象時.
struct Key { std::string first; std::string second; };
同時需要註意以下兩點:
1.聲明自己的哈希函數,重載operator()操作符,函數參數為自定義鍵值類型,返回為size_t:
struct KeyHash { std::size_t operator()(const Key& k) const { return std::hash<std::string>()(k.first) ^ (std::hash<std::string>()(k.second) << 1); } }; //位運算,移位運算
2.需要一個比較函數來比較hash鍵值是否相等
struct KeyEqual { bool operator()(const Key& lhs, const Key& rhs) const { return lhs.first == rhs.first && lhs.second == rhs.second; } };
使用時:
// 定義 KeyHash 與 KeyEqual 結構體並在模板中使用它們std::unordered_map<Key, std::string, KeyHash, KeyEqual> m6 = { { {"John", "Doe"}, "example"}, { {"Mary", "Sue"}, "another"} };
關於STL中的unordered_map
/*template <class Key, :主鍵的類型 * class T, :被映射的值的類型 * class Hash = hash<Key>, :一元,以一個key類型對象為參數 * 返回一個基於該對象的size_t類型的唯一值,類模板內部,使用其別名為hasher的成員類型 * class Pred = equal_to<Key>, 二元謂詞,以兩個Key類型的對象為參數,返回一個bool值 * 如果第一個參數等價為第二個參數,該bool值為true,否則為false.默認值為std::equal_to * class Alloc = allocator< pair<const Key, T> > * 容器內部用來管理內存分配及釋放的內存分配器的類型 * > class unordered_map; *template<class Key> struct hash; * */
寫的遞歸背包程序,感覺用遞歸還是很慢。
#include <iostream> #include <ctime> #include <string> #include <vector> #include <fstream> #include <unordered_map> #include <utility> #include <stack> #include <sstream> using namespace std; /***********物體屬性******/ class item { public: long value; //物體價值 int weight; //物體重量 item() : value(0), weight(0) {} }; /***********包含物體數量以及背包容量的鍵值對象,映射的value為目前容量下所能獲得的最優價值*************/ class Key { public: long weight; // int number; Key(int _num, long _weight) : number(_num), weight(_weight) {} }; struct KeyHash //自定義Hash函數 { size_t operator()(const Key& k) const { return std::hash<long>()(k.weight) ^ (std::hash<int>()(k.number) << 1); } }; struct KeyEqual //自定義操作符號 { bool operator()(const Key& lhs, const Key& rhs) const { return lhs.number == rhs.number && lhs.weight == rhs.weight; } }; class Knapsack { public: /**************構造函數讀取數據*************/ Knapsack() { ifstream fin("1.txt"); string line; stringstream stream; if(getline(fin, line)) { stream.clear(); stream << line; stream >> knapsack_size; stream >> num_of_items; } int cnt = 1; init_items(); while(getline(fin, line)) { long _value; long _weight; stream.clear(); stream << line; stream >> _value; stream >> _weight; items[cnt].value = _value; items[cnt].weight = _weight; cnt++; } } void init_items() { items.resize(num_of_items+1); } void dynamic() //遞歸動態規劃 { long max_value = make(num_of_items, knapsack_size); cout << "max_value:" << max_value << endl; } long make(int i_item, long weight) { Key find_key(i_item, weight); unordered_map<Key, long, KeyHash, KeyEqual >::iterator got = map.find(find_key); if( got != map.end()) { return got->second; } long value1 = 0; long value2 = 0; if(i_item == 0) //0件物品的情況 { Key temp_key(0, weight); map.insert(make_pair(temp_key, 0)); return 0; } value1 = make(i_item-1, weight); if(weight >= items[i_item].weight) { value2 = make(i_item-1, weight-items[i_item].weight) + items[i_item].value; if(value2 > value1) { Key temp_key(i_item, weight); map.insert(make_pair(temp_key, value2)); } else { Key kk(i_item, weight); map.insert(make_pair(kk, value1)); cout << value1 << endl; } } else { Key temp_key(i_item, weight); map.insert(make_pair(temp_key, value1)); } return value1 > value2 ? value1 : value2; } /**************根據hash表存儲的值找到最優解集合****************/ void reconstruct() { int i = num_of_items; int weight = knapsack_size; while(i > 0) { Key k1(i, weight); Key k2(i-1, weight); unordered_map<Key, long, KeyHash, KeyEqual>::iterator got1 = map.find(k1); unordered_map<Key, long, KeyHash, KeyEqual>::iterator got2 = map.find(k2); if(got1 != map.end() && got2 != map.end()) { if( (got1->second > got2->second) && (weight-items[i].weight >=0) ) { set.push_back(i); weight -= items[i].weight; i--; } else { i--; } } } } /********打印看結果*********/ void print() { ofstream fout1; fout1.open("out1.txt"); for(int i = 0; i < set.size(); i++) { fout1 << set[i] << " " ; } fcout << endl; } public: vector<item> items; int num_of_items; //物品個數 long knapsack_size; //背包容量 unordered_map<Key, long, KeyHash, KeyEqual> map; //自定義哈希鍵值 vector<int> set; //存儲最優解 }; int main() { clock_t start, end; start = clock(); Knapsack knapsack; knapsack.dynamic(); knapsack.reconstruct(); knapsack.print(); end = clock(); cout << "running time:" << (double)(end-start)/CLOCKS_PER_SEC << "s" << endl; return 0; }
自定義hash鍵C++