C++ STL学习笔记

来源:互联网 发布:淘宝怎么一键发布宝贝 编辑:程序博客网 时间:2024/06/08 07:39

C++ STL学习笔记一

为何要学习STL:

数据结构与算法是编程的核心,STL中包含各种数据结构和优秀的算法,确实值得深入学习,本文中虽然着重使用,但希望有心的朋友能多看看相关数据结构的实现,对于C++语言确实会有较大帮助。

 

STL库有多个版本,我采用的是SGI版本,编译安装方法请参考如下链接:

http://blog.csdn.net/hong201/archive/2009/07/06/4322975.aspx

PS:按照网上孟岩老师的安装方法,我出现了一些问题,后来按照上面文章所说的安装成功。

 

关于为何采用SGI版本STL库,目前我并没有较深感触,网上的说法是:

1.开源

2.可读性强

3.自设了一些容器,如slist、hash_set等

谈点我的感觉:运用VC自带库使用set容器时,发现可以通过迭代器来改变set的元素,改变会破坏红黑树,但编译通过,这个是比较严重的BUG。

可以的话建议安装SGI版本的STL库。

 

在笔记中,我主要介绍各容器的用法,工具选用VC6.0。关于自定义类型数据如何使用容器,这个是许多人纠结的问题,我尽量写一些例子。

因为是新学C++,所以文中不可避免会存在错误的地方,希望大家批评指正。

C++ STL学习笔记二 vector向量容器

/*
 *
 ********************************************
 *   vector容器的基础说明:
 ********************************************
 *
 * 可进行随机访问,并且实现了在容器的尾端插入新元素
 * Random Access Container 和 Back Insertion Sequence
 * 在尾端插入、删除元素的时间复杂度为O(1),其它位置为O(n),n为元素个数
 * 对于插入的元素可以动态调整所占空间
 * 使用vector必须使用宏语句#include <vector>
 *
 **************************************************************************************
 *
 * 创建vector对象:
 * 1.vector<int> a;
 * 2.vector<int> a(10);      //具有10个元素的对象a,每个元素默认值为0
 * 3.vector<char> a(5,'k');
 * 4.vector<char> b(a);      //vector<char> c(a.begin(),a.end())
 *
 **************************************************************************************
 *
 * 初始化赋值
 * void push_back(const T& value)
 *
 **************************************************************************************
 *
 * 遍历访问
 * reference operator[](size_type n)   //可用数组方式访问vector元素
 *
 **************************************************************************************
 *
 * 常用函数
 *
 * bool empty();
 * size_type size();size_type max_size();size_type capacity();
 * reference front();reference back();
 * void pop_back();void push_back();
 * void clear();
 *
 *
 *
 ********************************************
 * Author: cumirror   
 * Email: tongjinooo@163.com
 ********************************************
 *
 */

#include <iostream>
#include <vector>

int main()
{
 using namespace std;
 vector<int> a(10,5);
// 数组方式
 cout<<"数组"<<endl;
 a[0]=100;
 for(int s=0;s<a.size();s++){
  cout<<a[s]<<endl;
 }
// 迭代器方式
 cout<<"迭代器"<<endl;
 vector<int>::iterator i,iend;
 i=a.begin();
 iend=a.end();
 *i=101;
 for(vector<int>::iterator j=i;j!=iend;j++){
  cout<<*j<<endl;
 }
// 元素插入,插入位置为迭代器所指之前
// 注意:有元素插入后,原来的迭代器会失效
 cout<<"插入"<<endl;
 a.insert(a.begin(),102);
// 删除时注意,它是一个半闭区间
// 也支持 erase(iterator pos)单个元素的删除
 cout<<"删除"<<endl;
 a.erase(a.begin()+4,a.begin()+6);
 for(vector<int>::iterator k=a.begin();k!=a.end();k++){
  cout<<*k<<endl;
 }
// 反向遍历访问
 cout<<"反向访问"<<endl;
 vector<int>::reverse_iterator ri;
 for(ri=a.rbegin();ri!=a.rend();ri++){
  cout<<*ri<<endl;
 }
 return 0;
}

C++ STL学习笔记三 deque双端队列容器

/*
 *
 ********************************************
 *  deque双端队列容器的基础说明:
 ********************************************
 * 
 *
 * 可进行随机访问,在**头部和尾端**插入、删除元素,时间复杂度为O(1)
 * Random Access Container   Back Insertion Sequence   Front Insertion Sequence
 * 
 ************************************************************************************ 
 * 当考虑容器元素的内存分配策略和操作的性能时,deque较vector更具优势    *
 * map管理块,块中包含一组数据,内存分配更细致(以块为单位,使用二级的MAP进行管理) *
 ************************************************************************************ 
 * 
 * 使用deque必须使用宏语句#include <deque>
 *
 **************************************************************************************
 *
 * 创建deque对象:
 * 1.deque<int> a;
 * 2.deque<int> a(10);      //具有10个元素的对象a,每个元素默认值为0
 * 3.deque<char> a(5,'k');
 * 4.deque<char> b(a);      //deque<char> c(a.begin(),a.end())
 *
 **************************************************************************************
 *
 * 初始化赋值
 * void push_back(const T& value)
 *
 **************************************************************************************
 *
 * 遍历访问
 * reference operator[](size_type n)
 * iterator begin()
 * iterator end()
 *
 **************************************************************************************
 *
 * 常用函数
 *
 * bool empty();
 * size_type size();size_type max_size();  //无size_type capacity();reverse();
 * reference front();reference back();
 * void pop_front();void push_front();   //相较vector增加部分
 * void pop_back();void push_back();
 * void clear();
 *            //还有些函数直接见代码如erase();
 *
 *
 *
 ********************************************
 * Author: cumirror   
 * Email: tongjinooo@163.com
 ********************************************
 *
 */

#include <iostream>
#include <deque>

 

int main()
{
 using namespace std;
 deque<int> a(10,5);


// 数组方式
 cout<<"数组方式访问:"<<endl;
 a[0]=100;
 for(int s=0;s<a.size();s++){
  cout<<a[s]<<endl;
 }


// 迭代器方式
 cout<<"迭代器方式访问:"<<endl;
 deque<int>::iterator i,iend;
 i=a.begin();
 iend=a.end();
 *i=101;
 for(deque<int>::iterator j=i;j!=iend;j++){
  cout<<*j<<endl;
 }


//注意插入删除时迭代器的失效问题,偷个懒,大家可以看下面的网页,里面有说明但没介绍原因,其实这与各个容器是如何实现的有很大关系,若想深究可看《STL源码剖析》
//http://blog.csdn.net/jokenchang2000/archive/2008/07/01/2603485.aspx
 cout<<"插入"<<endl;
 a.insert(a.begin(),102);


// 删除时注意,它是一个半闭区间
// 也支持 erase(iterator pos)单个元素的删除
 cout<<"删除"<<endl;
 a.erase(a.begin()+4,a.begin()+6);
 for(deque<int>::iterator k=a.begin();k!=a.end();k++){
  cout<<*k<<endl;
 }


// 头部插入
 a.push_front(999);


// 反向遍历访问
 cout<<"反向访问"<<endl;
 deque<int>::reverse_iterator ri;
 for(ri=a.rbegin();ri!=a.rend();ri++){
  cout<<*ri<<endl;
 }


 deque<int> b;
 b.push_back(4);
 b.push_back(5);
 b.push_front(3);
 b.push_front(2);
 cout<<"互换"<<endl;
 b.swap(a);
 for(int l=0;l<a.size();l++){
  cout<<a[l]<<endl;
 }
 return 0;
}

 

C++ STL学习笔记四 list双向链表容器

/*
 *
 ********************************************
 *   list双向链表容器的基础说明:
 ********************************************
 *
 * list双向链表容器采用双向链表的数据结构来存储元素数据,可以高效查找、插入、删除容器元素
 *
 * Reversibe Container  Back Insertion Sequence  Front Insertion Sequence
 * 不同于vector,list查找、插入、删除元素的时间复杂度均为O(1)
 * 
 * 使用list必须使用宏语句#include <list>
 *
 **************************************************************************************
 *
 * 创建list对象:
 * 1.list<int> a;
 * 2.list<int> a(10);      //具有10个元素的对象a,每个元素默认值为0
 * 3.list<char> a(5,'k');
 * 4.list<char> b(a);      //list<char> c(a.begin(),a.end())
 *
 **************************************************************************************
 *
 * 初始化赋值
 * void push_back(const T& value)
 *
 **************************************************************************************
 *
 * 遍历访问
 * iterator begin()   //只能使用迭代器的方式进行遍历
 * iterator end()
 *  iterator rbegin();   //反向遍历
 *  iterator rbegin();
 * 
 **************************************************************************************
 *
 * 常用函数
 *
 * bool empty();
 * 
 * void pop_front(); void pop_back();
 * 
 * void push_front(const T&); void push_back(const T&);
 * iterator insert(iterator pos,const T&x); //注意它是插入到pos前
 *
 * iterator erase(iterator pos);
 * iterator erase(iterator first,iterator last);
 * void clear();
 * void remove(const T& value);
 *
 * void swap()         //通过交换头指针来实现元素的交换
 * //list内部提供的一个迁移操作
 * void transfer();       //transfer(iterator position,iterator first,iterator last)在A链表position位置前插入
 *            //B链表迭代器区间[first,last)的元素,并将这部分元素从B链表中抹去
 * void splice(iterator pos,list& X);   //调用transfer函数将一个链表的所有元素全部归并到当前链表,
 *            //并将链表对象X清空,
 * void splice(iterator pos,list& X,iterator i); //将X中迭代器i所指的元素归并到当前链表pos前,并将X中i所指元素抹去
 * 
 * void merge(list&X); //对两个链表进行归并,要求先排序,否则merge没有太大意义
 *
 * void unique();  //可将连续重复的元素删除,只保留一个
 *
 *
 *
 ********************************************
 * Author: cumirror   
 * Email: tongjinooo@163.com
 ********************************************
 *
 */

#include <list>
#include <iostream>   
#include <string>   
using namespace std;

struct student{
 char* name;
 int age;
 char* city;
 char* phone;
};

class studentNew{
public:
 char name[10];
 int age;
 char city[10];
 char phone[11];
 studentNew(){}
 studentNew(char* a,int b,char* c,char* d){
  strcpy(name,a);
  age=b;
  strcpy(city,c);
  strcpy(phone,d);
 }

//为何友元函数在类外定义,出现错误error C2593: 'operator >' is ambiguous
//friend bool operator < (studentNew&a,studentNew& b);
//friend bool operator > (studentNew&a,studentNew& b);
//friend bool operator == (studentNew&a,studentNew& b);

friend bool operator< (studentNew& a,studentNew& b){
 return strcmp(a.name,b.name)<0;
}
friend bool operator> (studentNew& a,studentNew& b){
 return strcmp(a.name,b.name)>0;
}
friend bool operator== (studentNew& a,studentNew& b){
 return strcmp(a.name,b.name)==0;
}

bool operator() (studentNew& a,studentNew& b){
 return strcmp(a.name,b.name)==-1;
}
};
/*
bool operator < (studentNew& a,studentNew& b){
 return strcmp(a.name,b.name)<0?true:false;
}
bool operator > (studentNew& a,studentNew& b){
 return strcmp(a.name,b.name)>0?true:false;
}
bool operator == (studentNew& a,studentNew& b){
 return strcmp(a.name,b.name)==0?true:false;
}
*/

int main(){
/* list<int> a;
 a.push_back(4);
 a.push_back(3);
 a.push_back(2);
 a.push_back(8);
 a.push_back(7);
 a.push_back(5);
 a.push_back(6);
 a.push_back(9);
 a.push_back(10);
 a.push_back(1);

// list的sort函数实现方法,如下

 list<int> carry;
 list<int> counter[64];
 int fill=0;
 while(!a.empty()){
 carry.splice(carry.begin(),a,a.begin());
 int i=0;
 while(i<fill&&!counter[i].empty()){
  counter[i].merge(carry);
  carry.swap(counter[i++]);
 }
 carry.swap(counter[i]);
 if(i==fill)++fill;
 }
 for(int i=1;i<fill;++i){
  counter[i].merge(counter[i-1]);
  a.swap(counter[fill-1]);
 }
 for(list<int>::iterator j=a.begin();j!=a.end();j++){
  cout<<*j<<endl;
 }
*/
// 其它函数使用示例,如下:

 student s[]={
  {"童进",23,"武汉","XXX"},
  {"老大",23,"武汉","XXX"},
  {"饺子",23,"武汉","XXX"}
 };
 list<student> classA;
 classA.push_back(s[0]);
 classA.insert(classA.begin(),s[1]);
 classA.push_back(s[3]);
 cout<<classA.begin()->name<<endl;
// classA.sort();                //对于自定义结构体,没有重载</>/==这些操作符,故无法排序

// 自己创建一个新类studentNew重载操作符再进行判断
 studentNew m1("童进",23,"武汉","XXX");
 studentNew m2("老大",23,"武汉","XXX");
 studentNew m3("饺子",23,"武汉","XXX");
 list<studentNew> classNew;
 classNew.push_back(m1);
 classNew.push_back(m2);
 classNew.push_back(m3);
// 判断友元函数是否起作用
 if( m1>m2 ){
  cout<<"新类中操作已经重载成功"<<endl;
 }
// 运用SGI STL库时
// 用函数对象studentNew,替换了greater<T>
 classNew.sort(studentNew());
// 若用VC自带的STL库时,下面这样书写即可实现.至于为何有这样的差异,目前我还不知
// classNew.sort(); 
 for(list<studentNew>::iterator m=classNew.begin();m!=classNew.end();m++){ //通过结果可以看出
  cout<<m->name<<endl;             //classNew已经进行了重新排列
 }                              

 list<string> classB;
 classB.push_back("童");
 classB.push_back("兰");
 classB.push_front("张");
 classB.push_back("童");
 classB.sort();                //对于string类型,有默认类型的greater<T>
 classB.unique();               //剔除重复数据
 for(list<string>::iterator k=classB.begin();k!=classB.end();k++){
  cout<<*k<<endl;
 }
 return 0;
}

C++ STL学习笔记五 slist单向链表容器

/*
 *
 ********************************************
 *   slist单向链表容器的基础说明:
 ********************************************
 *
 * slist是SGI C++STL自设的一个容器,要安装配置stlport才可以使用
 *
 * Front Insertion Sequence
 * slist为单向链表的泛化容器,故不再支持迭代器的反向移动
 *
 * 使用slist必须使用宏语句#include <slist>
 *
 **************************************************************************************
 *
 * 创建slist对象:
 * 1.slist<int> a;
 * 2.slist<int> a(10);         //具有10个元素的对象a,每个元素默认值为0
 * 3.slist<char> a(5,'k');
 * 4.slist<char> b(a);      
 * 5.slist(InputIterator first,InputIterator last); //slist<char> c(a.begin(),a.end())
 *
 **************************************************************************************
 *
 * 初始化赋值
 * void push_front(const T& value)
 *
 **************************************************************************************
 *
 * 遍历访问
 * 仅定义了向前移动的迭代器iterator和const_iterator
 * iterator begin();iterator end();
 *
 **************************************************************************************
 *
 * 常用函数
 *
 * void swap(slist&);
 * iterator insert_after(iterator pos,const T& x);  // 注意与前面不同的是,这里是在POS位置之后进行插入
 *              // vector、deque、list都是POS前插入
 * iterator insert(iterator pos,const T& X);   // 找到pos的前驱,再调用insert_after进行插入(pos前插入)
 *
 * void pop_front();
 *
 * iterator erase(iterator pos);
 * iterator erase(iterator first,iterator last);  // 注意是半闭区间[first,last)
 * void clear();
 * void remove(const T& x);       // 删除所有等于value的元素
 *
 * void splice(iterator pos,slist& x);
 * void splice(iterator pos,iterator i);
 *
 * void merge(slist& x);
 *
 * void sort();          // 按"<"关系进行排序
 * void unique();          // 删除重复元素,仅保留一个
 *
 *
 *
 ********************************************
 * Author: cumirror   
 * Email: tongjinooo@163.com
 ********************************************
 *
 */

#include <slist>
#include <string>
#include <iostream>
using namespace std;

//具体使用请参照前面的容器例子,这里不进行举例说明
int main(){
 slist<string> a;
 a.push_front("武汉");
 a.push_front("长沙");
 for(slist<string>::iterator i=a.begin();i!=a.end();i++){
  cout<<*i<<endl;
 }
 return 0;
}

C++ STL学习笔记六 bit_vector位向量容器




C++ STL学习笔记七 set容器

/*
 *
 ********************************************
 *   set集合容器的基础说明:
 ********************************************
 *
 * set集合容器使用RB-Tree的平衡二叉检索树的数据结构,不允许插入重复键值
 * 每个子树根节点的键值大于左子树所有节点的键值,而小于右子树所有节点的所有键值
 * 插入过程中要进行平衡处理,但检索过程效率高
 *
 * 提供了元素插入、删除、检索的功能
 * Unique Sorted Associative Container  Simple Associative Container
 *
 * 使用set必须使用宏语句#include <set>
 *
 **************************************************************************************
 *
 * 创建set对象:
 * 1.set<int> a;
 * 2.set(const key_compare& comp)      //指定一个比较函数对象comp来创建set对象
 *
 * srtuct strLess{ 
 *  bool operator()(const char* s1,const char* s2) const{
 *   return strcmp(s1,s2)<0;
 *  }
 * };
 * set<const char*,strLess> s(strLess());
 *
 *  3.set(const set&);         //set<int> b(a);
 * 4.set(first,last);         //set<char> c(a.begin(),a.end())
 * 5.set(first,last,const key_compare& comp);
 **************************************************************************************
 *
 * 元素的插入           //不允许插入重复键值
 * pair<iterator,bool> insert(const value_type& v); //可用于判断是否重复插入元素,对于特殊的信息可以提供这样的判断
 * iterator insert(iterator pos,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();     
 * reverse_iterator rbegin();reverse_iterator rend();
 *
 * iterator find(const key_type& k) const;
 *
 * 其它常用函数
 * bool empty() const;
 * size_type size() const;
 * void swap();
 *
 * //下面三个函数还没找到合适的例子,故不做说明
 * iterator lower_bound();iterator upper_bound();pair<iterator,iterator> equal_range();//上界、下届、确定区间
 *
 *
 *
 ********************************************
 **   cumirror ** tongjinooo@163.com **    **
 ********************************************
 *
 */


#include <set>
#include <iostream>

//自定义数据的插入
struct student{
 char name[20];
 int age;
 char city[20];
 char phone[20];
 bool operator()(const student& a,const student& b) const{
  return strcmp(a.name,b.name)<0;
 }
};

int main(){
 using namespace std;
 set<int> a;
 a.insert(10);
 a.insert(19);
 a.insert(8);
 a.insert(102);
 a.insert(1);
 pair<set<int>::iterator, bool> p=a.insert(18);
 if(p.second){
  cout<<"插入的新元素为:"<<*(p.first)<<endl;
 }
 else{
  cout<<"已存在该元素,重复插入"<<endl;
 }

 set<int>::iterator i=a.find(8);
// *i=250;         //与侯捷STL源码剖析237页所述有出入
 cout<<*i<<endl;       //原文为:企图通过迭代器改变元素是不被允许的
// a.insert(251);       //但VC6.0编译运行没有问题,只是set中的排序不正确了
           //即使重新插入251,因没有违反红黑树标准,错误不被修正
           //是否是因为STL版本问题:换STLport后编译果然报错
           //vc6.0中的STL库存在一定问题,大家注意
 cout<<"元素访问:"<<endl;
 for(set<int>::iterator j=a.begin();j!=a.end();j++){
  cout<<*j<<endl;
 }

// 为何称为容器,我认为在于对于用户自定义数据的包容,故写如下例子进行测试验证
// 也可以尝试用age作为判断条件
 student stu1={"童进",23,"武汉","XXX"};
 student stu2={"老大",28,"武汉","XXX"};    //老大,你成熟了5岁,哈哈
 student stu3={"饺子",23,"武汉","XXX"};
 set<student,student> b(student());
 b.insert(stu1);
 b.insert(stu2);
 b.insert(stu3);

 student stu4={"饺子123",88,"福州","XXX"};   
 pair<set<student,student>::iterator,bool> query=b.insert(stu4); 
 if(query.second==false)        //query.first返回插入元素的迭代器;query.second代表插入是否成功,true成功:false失败
  cout<<"重复元素插入会失败"<<endl;
 cout<<query.first->name<<endl;
 for(set<student,student>::iterator k=b.begin();k!=b.end();k++){
  cout<<k->name<<endl;
 }

// student test1={"老大",23,"武汉","XXX"};    //这样的元素,可以找到
// set<student,student>::iterator v=b.find(test1);
// student test2={"",23,"武汉","XXX"};     //无法找到
// set<student,student>::iterator v=b.find(test2);  
 student test3={"老大",99,"",""};     //可以找到,推测:
 set<student,student>::iterator v=b.find(test3);  //1.键值的设定依据key_compare()函数中的设置
 cout<<v->age<<endl;         //2.键值直接为定义数据类型中的第一个元素
              //结论:推测1正确。
              //可以修改operator()函数进行验证,也可以看后续multiset中的例子
 return 0;           
}

 

C++ STL学习笔记八 multiset多重集合容器

/*
 *
 ********************************************
 *   multiset多重集合容器的基础说明:
 ********************************************
 *
 * multiset多重集合容器使用RB-Tree的平衡二叉检索树的数据结构。
 * 允许将重复键值的元素插入到multiset中
 * 插入过程中要进行平衡处理,但检索过程效率高
 *
 * 提供了元素插入、删除、检索的功能
 * Sorted Associative Container  Simple Associative Container   Multiple Associative Container
 *
 * 使用multisetr必须使用宏语句#include <set>   //与set相同
 *
 **************************************************************************************
 *
 * 创建multisetr对象:
 * template < class Key, class Compare=less<Key>, class Alloc=alloc >
 *
 * 1.multisetr<int> a;
 * 2.multisetr(const key_compare& comp)    //指定一个比较函数对象comp来创建set对象,详细使用见main()中示例
 *  3.multisetr(const multisetr&);      //multisetr<int> b(a);
 * 4.multisetr(first,last);       //multisetr<char> c(a.begin(),a.end())
 * 5.multisetr(first,last,const key_compare& comp); //依据comp函数进行插入排序
 **************************************************************************************
 *
 * 元素的插入
 * iterator insert(const value_type& v);    //不再是返回pair,而是插入的迭代器位置
 * iterator insert(iterator pos,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();     //企图通过迭代器改变元素是不被允许的
 * reverse_iterator rbegin();reverse_iterator rend();
 *
 * iterator find(const key_type& k) const;
 * pair<iterator,iterator> equal_range(const key_type& k) const;//返回的pair对象,
 *                //first为lower_bound(k);大于等于k的第一个元素位置
 *                //second为upper_bound();大于k的第一个元素位置
 *
 * 其它常用函数
 * bool empty() const;
 * size_type size() const;
 * size_type count(const key_type& k) const;   //返回键值等于k的元素个数
 * void swap();
 *
 * //main中包含了一下函数的简单例子
 * iterator lower_bound();iterator upper_bound();pair<iterator,iterator> equal_range();//上界、下届、确定区间
 *
 *
 *
 ********************************************
 **   cumirror ** tongjinooo@163.com **    **
 ********************************************
 *
 */

#include <set>
#include <iostream>

// 自定义数据的插入
struct student{
 char name[20];
 int age;
 char city[20];
 char phone[20];
};

// 这里采用函数对象的方式设置,与set中有不同,key设置为city,注意应设置为public
class stuCmp{
public:
 bool operator()(const student& a,const student& b) const{
  return strcmp(a.city,b.city)<0;
 }
};

// 对于一些基本数据类型,如int,string等可参照set
int main(){
 using namespace std;
 student stu1={"童进",23,"长沙","XXX"};
 student stu2={"老大",28,"武汉","XXX"};    //老大,你成熟了5岁,哈哈
 student stu3={"饺子",23,"福州","XXX"};
// multiset<student,stuCmp> b;       
 multiset<student,stuCmp> b(stuCmp());
 b.insert(stu1);
 b.insert(stu2);
 b.insert(stu3);
// 武汉同学最多,只是现在大家又都天各一方
 student stu4={"小芳",23,"武汉","XXX"};
 student stu5={"黄庆",23,"武汉","XXX"};
 student stu6={"英俊",23,"武汉","XXX"};
 b.insert(stu4);
 b.insert(stu5);
 b.insert(stu6);

 for(multiset<student,stuCmp>::iterator i=b.begin();i!=b.end();i++){
  cout<<i->name<<endl;
 }

 student key={"",99,"武汉","XXX"};
 cout<<"武汉朋友数目:"<<b.count(key)<<endl;
 cout<<"武汉的第一个朋友:"<<b.lower_bound(key)->name<<endl;
 cout<<"武汉最后一个朋友:"<<(--b.upper_bound(key))->name<<endl; // 这里武汉是最后的,再大于这个键值,就会返回end()指向头节点,所以--
 for(multiset<student,stuCmp>::reverse_iterator j=b.rbegin();j!=b.rend();j++){
  cout<<j->name<<endl;
 }

// 验证set中的猜测,此时键值为city
 student test={"路人甲",99,"武汉","XXX"};    
 multiset<student,stuCmp>::iterator v=b.find(test); //返回第一个与键值相等的迭代器  
 cout<<"寻找武汉的路人甲:"<<v->name<<endl;

// 元素搜索
 cout<<"搜索武汉的朋友们:"<<endl;
 pair<multiset<student,stuCmp>::iterator,multiset<student,stuCmp>::iterator> p=b.equal_range(test);
 for(multiset<student,stuCmp>::iterator k=p.first;k!=p.second;k++){
  cout<<k->name<<endl;
 }
 return 0;
}

C++ STL学习笔记九 map映照容器

/*
 *
 ********************************************
 *   map映照容器的基础说明:
 ********************************************
 *
 * map映照容器:容器的数据结构采用红黑树进行管理,插入的元素键值不允许重复
 * map的所有元素都是pair:第一元素为键值(key),不能修改;第二元素为实值(value),可被修改
 * 
 * map和list一样,使用insert或erase后,操作前的所有迭代器,在操作完成后依然有效
 * []:不仅可用键值的数组方式访问元素的映照数据,还可用来添加map容器的元素 //main中示例
 * 
 * Sorted Associative Container  Pair Associative Container   Unique Associative Container
 *
 * 使用map必须使用宏语句#include <map>   
 *
 **************************************************************************************
 *
 * 创建map对象:
 * 1.map<char,int,greater<char> > a;    //元素键值类型为char,映照数据类型为int,键值的比较函数对象为greater<char>
 * 2.map(const key_compare& comp)     //指定一个比较函数对象comp来创建map对象
 *  3.map(const map&);      //map<int,char*> b(a); //此时使用默认的键值比较函数less<int>
 * 4.map(first,last);         
 * 5.map(first,last,const key_compare& comp);  
 *
 * //Example:
 * pair<const int ,char> p1(1,'a');
 * pair<const int ,char> p2(2,'b');
 * pair<const int ,char> p3(3,'c');
 * pair<const int ,char> p4(4,'d');
 * pair<const int ,char> pairArray[]={p1,p2,p3,p4};
 * map<const int,char> m4(pairArray,pairArray+5);
 * map<const int,char> m3(m4);
 * map<const int,char,greater<const int> > m5(pairArray,pairArray+5,greater<const int>());
 *
 **************************************************************************************
 *
 * 元素的插入
 * //typedef pair<const key,T> value_type;
 * pair<iterator,bool> insert(const value_type& v);    
 * iterator insert(iterator pos,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();     //企图通过迭代器改变元素是不被允许的
 * reverse_iterator rbegin();reverse_iterator rend();
 *
 * iterator find(const key_type& k) const;
 * pair<iterator,iterator> equal_range(const key_type& k) const;//返回的pair对象,
 *                //first为lower_bound(k);大于等于k的第一个元素位置
 *                //second为upper_bound();大于k的第一个元素位置
 *
 * 其它常用函数
 * bool empty() const;
 * size_type size() const;
 * void swap();
 *
 * iterator lower_bound();iterator upper_bound();pair<iterator,iterator> equal_range();//上界、下届、确定区间
 *
 *
 *
 ********************************************
 **   cumirror ** tongjinooo@163.com **    **
 ********************************************
 *
 */

#include <map>
#include <string>
#include <iostream>

// 基本操作与set类似,牢记map中所有元素都是pair
// 对于自定义类,初学者会觉得比较函数如何构造很麻烦,这个可以参照前面的书写示例
// 但若设置键值为int或char类型,无须构造比较函数

struct student{
 char* name;
 int age;
 char* city;
 char* phone;
};

struct strCmp{
 bool operator () (const char* a,const char* b) const{
  return strcmp(a,b)<0;
 }
};

struct strCmpBig{
 bool operator () (const char* a,const char* b) const{
  return strcmp(a,b)>0;
 }
};

int main(){
 using namespace std;
// 使用[]操作符
 map<string,int> animal;
 animal[string("fish")]=12;
 animal[string("dog")]=10;
 animal[string("cat")]=5;
 cout<<animal["cat"]<<endl;

// string类有默认的比较函数,故下面的语句可以执行,若换为char*类型,则执行会出现问题
// 迭代器i指向pair类型
 for(map<string,int>::iterator i=animal.begin();i!=animal.end();i++){
  cout<<"The number of "<<i->first<<" : "<<i->second<<endl;
 }

 student s[]={
  {"童进",23,"武汉","XXX"},
  {"老大",23,"武汉","XXX"},
  {"饺子",23,"武汉","XXX"}
 };
  pair<int,student> p1(4,s[0]);
  pair<int,student> p2(2,s[1]);
  pair<int,student> p3(3,s[2]);
 map<int,student> a;
 a.insert(p1);
 a.insert(p2);
 a.insert(p3);
// 按照键值2、3、4进行排列输出
 for(map<int,student>::iterator j=a.begin();j!=a.end();j++){      
  cout<<"The name: "<<j->second.name<<"   "<<"age: "<<j->second.age<<"   "
   <<"city: "<<j->second.city<<"   "<<"phone: "<<j->second.phone<<endl;
 }

// 思考,这是按照键值进行排列,若我想变换,按照name或者年龄进行重新排列,那么又该如何实现呢?
 
 cout<<"新的排列"<<endl;
  pair<const char*,student> q1(s[0].name,s[0]);
  pair<const char*,student> q2(s[1].name,s[1]);
  pair<const char*,student> q3(s[2].name,s[2]);

 student testStu={"AB",23,"武汉","XXX"};

// 为何要采用函数对象的形式,而不只能是函数,这个与C++内部实现机制有关

 map<const char*,student,strCmp> b;
 b.insert(q1);
 b.insert(q2);
 b.insert(q3);

// insert函数的测试,观察其放回迭代器的值,可改变名字看看,插入位置视实际情况定
// 返回插入元素的迭代器
  pair<const char*,student> q4(testStu.name,testStu);
 map<const char*,student,strCmp>::iterator test=b.insert(b.begin()++,q4);
 cout<<test->second.name<<endl;

 for(map<const char*,student,strCmp>::iterator k=b.begin();k!=b.end();k++){      
  cout<<"The name: "<<k->second.name<<"   "<<"age: "<<k->second.age<<"   "
   <<"city: "<<k->second.city<<"   "<<"phone: "<<k->second.phone<<endl;
 }

// 拷贝的时候也可以进行函数对象的设置,那如果函数对象变换了,能实现顺序的变化吗?
// 目前还没实现,不知道具体可行吗?以后再进行测试吧

// 个人观点:不可行。函数对象比较的是key,若重新排列,key不能变换,
// 那么所谓的重新排列,岂不仅仅是反序排列,而反序输出map已经具有了这样的函数了。

 cout<<"拷贝时实现重新排列"<<endl;     //并未实现
 map<const char*,student,strCmp> c(b);
 for(map<const char*,student,strCmp/*strCmpBig*/>::iterator m=c.begin();m!=c.end();m++){      
  cout<<"The name: "<<m->second.name<<"   "<<"age: "<<m->second.age<<"   "
   <<"city: "<<m->second.city<<"   "<<"phone: "<<m->second.phone<<endl;
 } 

 return 0;
}

C++ STL学习笔记十 multimap多重映照容器

/*
 *
 ********************************************
 *  multimap多重映照容器的基础说明:
 ********************************************
 *
 * multimap多重映照容器:容器的数据结构采用红黑树进行管理
 * multimap的所有元素都是pair:第一元素为键值(key),不能修改;第二元素为实值(value),可被修改
 *
 * multimap特性以及用法与map完全相同,唯一的差别在于:
 * 允许重复键值的元素插入容器(使用了RB-Tree的insert_equal函数) 
 * 因此:
 * 键值key与元素value的映照关系是多对多的关系
 * 没有定义[]操作运算 
 * 
 * Sorted Associative Container  Pair Associative Container   Unique Associative Container
 *
 * 使用multimap必须使用宏语句#include <map>          
 *
 **************************************************************************************
 *
 * 创建multimap对象:
 * 1.multimap<char,int,greater<char> > a;    //元素键值类型为char,映照数据类型为int,键值的比较函数对象为greater<char>
 * 2.multimap(const key_compare& comp)     //指定一个比较函数对象comp来创建map对象
 *  3.multimap(const multisetr&);      //multimap<int,char*> b(a); //此时使用默认的键值比较函数less<int>
 * 4.multimap(first,last);         
 * 5.multimap(first,last,const key_compare& comp);  
 *
 * //Example:
 * pair<const int ,char> p1(1,'a');
 * pair<const int ,char> p2(2,'b');
 * pair<const int ,char> p3(3,'c');
 * pair<const int ,char> p4(4,'d');
 * pair<const int ,char> pairArray[]={p1,p2,p3,p4};
 * multimap<const int,char> m4(pairArray,pairArray+5);
 * multimap<const int,char> m3(m4);
 * multimap<const int,char,greater<const int> > m5(pairArray,pairArray+5,greater<const int>());
 *
 **************************************************************************************
 *
 * 元素的插入
 * //typedef pair<const key,T> value_type;
 * pair<iterator,bool> insert(const value_type& v);    
 * iterator insert(iterator pos,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();     //企图通过迭代器改变元素是不被允许的
 * reverse_iterator rbegin();reverse_iterator rend();
 *
 * iterator find(const key_type& k) const;
 * pair<iterator,iterator> equal_range(const key_type& k) const;//返回的pair对象,
 *                //first为lower_bound(k);大于等于k的第一个元素位置
 *                //second为upper_bound();大于k的第一个元素位置
 *
 * 其它常用函数
 * bool empty() const;
 * size_type size() const;
 * size_type count(const key_type& k) const;   //返回键值等于k的元素个数
 * void swap();
 *
 * iterator lower_bound();iterator upper_bound();pair<iterator,iterator> equal_range();//上界、下届、确定区间
 *
 *
 *
 ********************************************
 **   cumirror ** tongjinooo@163.com **    **
 ********************************************
 *
 */

#include <map>
#include <string>
#include <iostream>

// 基本操作与set类型,牢记map中所有元素都是pair
// 对于自定义类,初学者会觉得比较函数如何构造很麻烦,这个可以参照前面的书写示例
// 但若设置键值为int或char类型,无须构造比较函数

struct student{
 char* name;
 int age;
 char* city;
 char* phone;
};

int main(){
 using namespace std;

 student s[]={
  {"童进",23,"武汉","XXX"},
  {"老大",23,"武汉","XXX"},
  {"饺子",23,"武汉","XXX"},
  {"王老虎",23,"武汉","XXX"},
  {"周润发",23,"武汉","XXX"},
  {"周星星",23,"武汉","XXX"}
 };
  pair<int,student> p1(4,s[0]);
  pair<int,student> p2(2,s[1]);
  pair<int,student> p3(3,s[2]);
  pair<int,student> p4(4,s[3]);  //键值key与p1相同
  pair<int,student> p5(5,s[4]);
  pair<int,student> p6(6,s[5]);
 multimap<int,student> a;
 a.insert(p1);
 a.insert(p2);
 a.insert(p3);
 a.insert(p4);
 a.insert(p5);
 a.insert(p6);
 typedef multimap<int,student>::iterator int_multimap;
 pair<int_multimap,int_multimap> p=a.equal_range(4);
 int_multimap i=a.find(4);
 cout<<"班上key值为"<<i->first<<"的学生有:"<<a.count(4)<<"名,"<<"   他们是:"<<endl;
 for(int_multimap k=p.first;k!=p.second;k++){
  cout<<k->second.name<<endl;
 }
 cout<<"删除重复键值的同学"<<endl;
 a.erase(i);
 cout<<"现在班上总人数为:"<<a.size()<<".   人员如下:"<<endl;
 for(multimap<int,student>::iterator j=a.begin();j!=a.end();j++){      
  cout<<"The name: "<<j->second.name<<"      "<<"age: "<<j->second.age<<"   "
   <<"city: "<<j->second.city<<"      "<<"phone: "<<j->second.phone<<endl;
 }

 return 0;
}

C++ STL学习笔记十一 hash_set哈希集合容器

/*
 *
 ************************************************************************************
 *      hash_set哈希集合容器的基础说明:
 ************************************************************************************
 *
 * hash_set哈希集合容器:使用hashtable数据结构的具有高效数据检索的关联容器
 * 
 * 不提供反向迭代器,只有前向迭代器iterator和const_iterator
 * 不允许插入重复的元素键值
 * Hashed Associative Container  Simple Associative Container   Unique Associative Container
 *
 * 目前还不是C++的标准容器,只是SGI C++ STL的一个扩展容器
 * 使用hash_set必须使用宏语句#include <hash_set>          
 * 
 **************************************************************************************
 *
 * 创建hash_set对象:
 * 1.hash_set<int> hs;        //键值比较使用默认的函数对象equal_to<Value>
 * 2.hash_set(size_type n);      //在质数列表中找出第一个大于等于n的质数作为表长:hash_set<int> hs(100);
 *  3.hash_set(size_type n,const hasher& h);  //hash函数对象为h
 * 4.hash_set(size_type n,const hasher& h,const key_equal& k);//键值比较函数对象k         
 * 5.hash_set(const hash_set& h);     //用一个hash集合容器拷贝生成另一个hash集合容器:hash_set<int> hs2(hs); 
 *
 **************************************************************************************
 *
 * 元素的插入
 * //typedef pair<const key,T> value_type;
 * pair<iterator,bool> insert(const value_type& v);//second:返回true/false插入成功标志   
 * void insert(iterator pos,const value_type& v);
 *
 **************************************************************************************
 *
 * 元素的删除
 * 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;    //对于非默认类型如char*,在搜素时应定义相关的函数对象
 *
 * 其它常用函数
 * bool empty() const;
 * size_type size() const;
 * size_type bucket_count(const key_type& k) const; //获得hash表的表长
 * void swap();
 * resize();
 * iterator lower_bound();iterator upper_bound();pair<iterator,iterator> equal_range();//上界、下届、确定区间
 *
 * 在SGI STL中,提供了以下hash函数:
 * struct hash<char*>
 * struct hash<const char*>
 * struct hash<char>
 * struct hash<unsigned char>
 * struct hash<signed char>
 * struct hash<short>
 * struct hash<unsigned short>
 * struct hash<int>
 * struct hash<unsigned int>
 * struct hash<long>
 * struct hash<unsigned long>
 *
 * hash函数决定了如何划分散列表
 *
 *
 *
 ********************************************
 **   cumirror ** tongjinooo@163.com **    **
 ********************************************
 *
 */

#include <hash_set>
#include <iostream>


struct student{
 char* name;
 int age;
 char* city;
 char* phone;
};
//自定义数据的比较函数
class stuequal{
public:
 bool operator() (const student& a,const student& b){
  return strcmp(a.city,b.city)==0;      //不允许同名,name为键值
 }               //将name换为city测试下
};
//自定义数据的hash函数
//typedef unsigned int size_t;
struct stu_hash{
 size_t operator()(const student& stu) const
 {
  unsigned long res = 0;
  char* s=stu.city;
  for( ; *s; ++s ){
   res=5*res+*s;
  }
  return size_t(res);
 }
};

//针对字符串的比较函数对象
class strequal{
public:
 bool operator () (const char* a,const char* b)const{
  return strcmp(a,b)==0;         
 }
};

int main(){
 using namespace std;

 hash_set<const char*,hash<const char*>,strequal> a;
 a.insert("tongjin");
 a.insert("cumirror");
 a.insert("makelaugh");
 a.insert("feiguodeyun");

// hash<const char*>默认提供的hash函数对象
 hash_set<const char*,hash<const char*>,strequal>::const_iterator b=a.find("tongjin");
 cout<<*b<<" is "<<(b!=a.end()?"present":"not present")<<endl;

// 对于自定义类型数据,使用hash相关容器时应构造hash函数对象、比较函数对象
// 注意区别hash函数对象与比较函数对象各自的作用
 student s[]={
  {"童进",23,"长沙","XXX"},
  {"老大",23,"武汉","XXX"},
  {"饺子",23,"福州","XXX"},
  {"王老虎",23,"地球","XXX"},
  {"周润发",23,"香港","XXX"},
  {"周星星",23,"香港","XXX"},   //city重复
  {"童进",23,"香港","XXX"}   //name重复、city也有重复
 };         

 hash_set<student,stu_hash,stuequal> c;
 c.insert(s[0]);
 c.insert(s[1]);
 c.insert(s[2]);
 c.insert(s[3]);
 c.insert(s[4]);
 c.insert(s[5]);
 c.insert(s[6]);
// 注意hash容器并不能实现排序
 for(hash_set<student,stu_hash,stuequal>::iterator i=c.begin();i!=c.end();i++){
  cout<<i->name<<" "<<i->age<<" "<<i->city<<endl;
 }
 return 0;
}

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 ** tongjinooo@163.com **    **
 ********************************************
 *
 */

#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;
}