STL学习笔记

来源:互联网 发布:大庆网络问政平台下载 编辑:程序博客网 时间:2024/06/05 07:48

数据结构与算法是编程的核心,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;
}




为何要学习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++,所以文中不可避免会存在错误的地方,希望大家批评指正。

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

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

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

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

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

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

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

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

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