1.operator [] 。这个[]的作用很大,不仅可以把key所对应value的引用取出来,还有插入的功能。展示一个基本的使用方法先:
using namespace std; ... map<string,int> elem; .... //insert operation ... //get inserted value string keyword; int freq = elem[keyword];
这样就可以把map中key对应的value取出来!如果我输入的keyword,这个map里面没有怎么办?这时就使用了[]的插入功能。如果用户填入了一个map没有的keyword。operator []可以插入一个新的pair。并调用mapped data的构造函数。有代码为证!
1 struct NumIDF 2 { 3 int num; 4 bool showup; 5 NumIDF() 6 { 7 num = 0; 8 showup = false; 9 cout << "set to 0 and false" << endl; 10 } 11 }; 12 ... 13 map<string,NumIDF> m_IDF; 14 //insert elements 15 ... 16 //query elements 17 string newKeyword;//这个词m_IDF中没有 18 if(!m_IDF[newKeyword].showup) 19 { 20 cout << "construct a new one" << endl; 21 }
如果把上面代码的输出是
set to 0 and false construct new one
也就是说,当在[]内输入了一个新的key之后,map可以自动添加一个新的pair,新pair的key就是输入的newkeyword。而mapped data就是经过初始化之后的实例。这个功能非常好。我以前都是先用find函数找一下,如果是新的,再手动添加。那样的话会非常繁琐。
2.map的iterator的使用
说实在的,我用iterator用的比较少。所以犯了几个很低级的错误。写在这里也给自己提个醒。我出错的情况是这样的:我想实现一个类似下面代码要实现的功能。
vector<int> a; for(int i = 0; i < a.size()-1; i++) { for(int j = i+1, j < a.size(); j++) { //some operation about i and j } }
我想用iterator来实现上面的功能,于是就有了下面悲壮的一幕:
map<string,int>::iterator iterI; .... //这是错误的啊! int i = 5; iterI = iterI + i; //这是错误的啊!
我想当然的以为,iterator+多少就会往后面跳多少。可以编译不过啊!出了一大堆错!!有木有!!!于是我用了下面的方法
1 map<string,int> m_Tree; 2 map<string,int>::iterator iterI = m_Tree.begin(); 3 map<string,int>::iterator iterJ; 4 int i = 0; 5 for( ; i < m_Tree.size()-1; ++iterI,i++) 6 { 7 //iterJ = m_Tree.begin(); 8 //advance(iterJ, i+1); 9 iterJ = iterI; 10 iterJ++; 11 for(; iterJ != m_Tree.end(); iterJ++) 12 { 13 float s = S((iterI->dvmap),(iterJ->dvmap)); 14 if(s > mostSim) 15 {//this is the pair 16 mostSim = s; 17 sp.s1 = iterI; 18 sp.s2 = iterJ; 19 } 20 } 21 }
我想得到iterI所指向的下一个元素,于是我采用了第9,10行的方法。其实第7,8行的代码也是可以的,只是不如9,10行的高效!如果你有更好的方法可以带到这个功能,请你告诉我哈!
3.性能方面,不要让std复制内存,传指针吧!
在计算文档相似性的时候要用到一个多维的文档向量。这个大向量是使用了std::vector来处理。在性能方面我注意到了两点。
1)使用reserve申请足够多的内存。为push_back做准备
2)使用push_back的时候要注意。如果在函数体内声明了一个vector<float>。这个vector的size超大。这是你想把它push_back给类的私有成员的时候势必要复制大量的内存。
基于上面的两点我采用了下面的方法
1 vector<float> dv; 2 pair<map<string,vector<float> >::iterator,bool> pr; 3 pr = m_TF_IDF.insert(pair<string,vector<float> >(filename, dv)); 4 vector<float>& rkdv = pr.first->second; 5 rkdv.reserve(m_IDF.size());
其中m_TF_IDF是类的私有成员,我现insert了一个空的vector。然后把这个空vector的引用取出来,如第4行所示。然后就可以用大vector的引用来push_back新的数据,这样就免去了内存的复制。
指针的使用,在避免内存复制上,指针也是一个快捷高效的实现方式。在我的程序中,不知一个地方使用了前面所说的超大vector<float>。为了让想用vector<float>的人都能用上他,我把vector<float>的指针传了出来。 我定义了如下所示的结构体:
struct dvPair { string names; map<string,vector<float>*> dvmap; };
我传入的是vector<float>的指针,而不是vector<float>!
也就是这么多了,别没什么了