C++ STL學習筆記十二 hash_map映照容器

/*
 *
 ************************************************************************************
 *       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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章