1. 程式人生 > >自定義hash鍵C++

自定義hash鍵C++

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++