/*
*
************************************************************************************
* hash_map映照容器的基礎說明:
************************************************************************************
*
* hash_map哈希映照容器:使用hash表的數據結構,插入的元素鍵值不允許重複
* hash_map的所有元素都是pair:第一元素爲鍵值(key),不能修改;第二元素爲實值(value),可被修改
*
* 不提供反向迭代器,只有前向迭代器iterator和const_iterator
* 可定義出操作符[]
*
* Hashed Associative Container Pair Associative Container Unique Associative Container
*
* 目前還不是C++的標準容器,只是SGI C++ STL的一個擴展容器
* 使用hash_map必須使用宏語句#include <hash_map>
* 可與map作比較: hash_map檢索時使用的鍵值比較次數少,容器需佔用較多的空間,用迭代器遍歷出來的元素是非排序的;
* map則使用鏈表的二分法進行檢索,空間使用率高,遍歷出來的元素是排序的,而且可提供反向迭代器。
*
**************************************************************************************
*
* 創建map對象:
* 1.hash_map<char,int> a; //鍵值類型爲char,映照數據類型爲int,默認表長爲193
* 2.hash_map(size_type n); //hash_map<char,int> a(300);此時表長爲389
* * 3.hash_map(size_type n,const hasher& h);
* * 4.hash_map(size_type n,const hasher& h,const key_equal& k);
* 5.hash_map(const hash_map&);
*
* //Example4:
* struct strequal{
* bool operator() (const char* a,const char* b) const {
* return strcmp(a,b)==0;}
* };
* hash_map<char*,int,hash<char*>,strequal> hm(300,hash<char*>(),strequal());
*
**************************************************************************************
*
* 元素的插入
* //typedef pair<const key,T> value_type;
* pair<iterator,bool> insert(const value_type& v);
* void insert(first,last);
*
**************************************************************************************
*
* 元素的刪除
* void erase(iterator pos);
* size_type erase(const key_type& k); //刪除等於鍵值k的元素
* void erase(first,last); //刪除[first,last)區間的元素
* void clear();
*
**************************************************************************************
*
* 訪問與搜索
*
* iterator begin();iterator end(); //企圖通過迭代器改變元素是不被允許的
*
* iterator find(const key_type& k) const;
* pair<iterator,iterator> equal_range(const key_type& k) const; //此時鍵值不允許重複,故沒有太大用途
*
* 其它常用函數
* bool empty() const;
* size_type size() const;
* size_type bucket_count(const key_type& k) const; //獲得hash表的表長
* void swap();
* resize();
* void swap();
*
* iterator lower_bound();iterator upper_bound();pair<iterator,iterator> equal_range();//上界、下屆、確定區間
*
*
*
********************************************
** cumirror ** [email protected] ** **
********************************************
*
*/
#include <string>
#include <hash_map>
#include <iostream>
using namespace std;
template<class Key,class NameType,class AgeType,class AdressType>
struct StudentRecord_tag{ //學生記錄結構體
struct StudentInfo_tag{
NameType name;
AgeType age;
AdressType city;
};
typedef Key IdType;
typedef StudentInfo_tag StudentInfo;
IdType id;
StudentInfo stuinfo;
};
//針對最後的示例,設置的hash函數
struct myhash{
size_t operator() (const string& str) const
{
unsigned long __h = 0;
for (size_t i = 0 ; i < str.size() ; i ++)
__h = 5*__h + str[i];
return size_t(__h);
}
};
class str_compare{
public:
bool operator()(const string& str1,const string& str2)const
{
return str1==str2;
}
};
int main(){
// 使用[]操作符
hash_map<string,int> animal;
animal[string("fish")]=12;
animal[string("dog")]=10;
animal[string("cat")]=5;
cout<<animal["cat"]<<endl;
// 結構體A中定義的結構體B,在結構體A外可以使用嗎?
// StudentInfo_tag a; //直接這樣是無法使用的,若想獨立使用可以參照下面的方法
// typedef StudentRecord_tag<int,char*,int,char*> StudentRecorda;
// StudentRecorda::StudentInfo_tag testa;
typedef StudentRecord_tag<int,char*,int,char*> StudentRecord;
StudentRecord stuArray[]={
{192,"黃慶",23,"北京"},
{191,"童進",23,"長沙"},
{194,"餃子",23,"福州"},
{193,"小芳",23,"寧波"},
};
// 此處應該留意typedef的使用
hash_map<StudentRecord::IdType,StudentRecord::StudentInfo> school;
typedef pair<const StudentRecord::IdType,StudentRecord::StudentInfo> value_type;
for(int i=0;i<4;i++){
value_type p(stuArray[i].id,stuArray[i].stuinfo);
school.insert(p);
}
// 測試是否插入成功
cout<<school[193].name<<endl;
// 採用迭代器訪問,注意map類型容器,其元素爲pair類型,pair中first/second要明白
hash_map<StudentRecord::IdType,StudentRecord::StudentInfo>::iterator j;
cout<<"同學"<<" "<<"住址"<<endl;
for(j=school.begin();j!=school.end();j++){
cout<<j->second.name<<" "<<
j->second.city<<endl;
}
// 其它函數示例
// 元素的重複插入
value_type p(stuArray[0].id,stuArray[0].stuinfo);
pair<hash_map<const StudentRecord::IdType,StudentRecord::StudentInfo>::iterator,bool> insertReturn;
cout<<(
(insertReturn=school.insert(p)).second==true?"插入成功":"插入失敗"
)
<<endl;
cout<<"總人數:"<<school.size()<<endl;
cout<<"hash表長:"<<school.bucket_count()<<endl;
// 如下思考:
// 上例中key:IdType爲int型,故不用定義hash函數對象,也可將IdType定爲string類型,形如"0120504140227"這樣的類型
// 此時需要定義hash函數,具體解法如下:(在原來定義的變量名後+1)
// 原想在上面例子的基礎上進行改進,但不成功,可能與string類型內存分配模式有關
// typedef StudentRecord_tag< string,char*,int,char*> StudentRecord1;
// StudentRecord1 stuArray1[]={ //不好意思,你們暫時先入我班吧
// {string("0120504140208"),"黃慶",23,"北京"},
// {string("0120504140227"),"童進",23,"長沙"},
// {string("0120504140209"),"餃子",23,"福州"},
// {string("0120504140216"),"小芳",23,"寧波"},
// };
// hash_map<StudentRecord1::IdType,StudentRecord1::StudentInfo,myhash> school1;
// typedef pair<const StudentRecord1::IdType,StudentRecord1::StudentInfo> value_type1;
// for(int i=0;i<4;i++){
// value_type1 p(stuArray1[i].id,stuArray1[i].stuinfo);
// school.insert(p);
// }
// 在網上看到一份較爲簡單的例子,根據自己的稍稍改了下(注意前面的hash函數與比較函數)
hash_map<string,string,myhash,str_compare> myHash;
string strArray[][2]={
{"0120504140227","童進"},
{"0120504140236","zyl"},
{"0120504140216","hq"},
{"0120504140209","jz"},
};
typedef pair<string,string> value_type2;
for(int k=0;k<4;k++){
value_type2 p(strArray[k][0],strArray[k][1]);
myHash.insert(p);
}
hash_map<string,string,myhash,str_compare>::iterator p1;
for(p1=myHash.begin();p1!=myHash.end();p1++){
cout<<p1->first<<" "<<
p1->second<<endl;
}
return 0;
}