郭颂歌曲:STL map

来源:百度文库 编辑:九乡新闻网 时间:2024/05/03 01:57:14
映射和多重映射基于某一类型Key的键集的存在,提供对T类型的数据进行快速和高效的检索。对map而言,键只是指存储在容器中的某一成员。Map不支持副本键,multimap支持副本键。Map和multimap对象包涵了键和各个键有关的值,键和值的数据类型是不相同的,这与set不同。set中的key和value是Key类型的,而map中的key和value是一个pair结构中的两个分量。

Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。这里说下map内部数据的组织,map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处。

 

Map是标准关联式容器associative container)之一,一个map是一个键值对序列,即(key ,value)对。它提供基于key的快速检索能力,在一个map中key值是唯一的。map提供双向迭代器,即有从前往后的(iterator),也有从后往前的(reverse_iterator)。

map要求能对key进行<操作,且保持按key值递增有序,因此map上的迭代器也是递增有序的。如果对于元素并不需要保持有序,可以使用hash_map

map中key值是唯一的,如果马匹中已存在一个键值对(昵称,密码):("skynet",407574364),而我们还想插入一个键值对("skynet",472687789)则会报错(不是报错,准确的说是,返回插入不成功!)。而我们又的确想这样做,即一个键对应多个值,幸运的是multimap可是实现这个功能。 //先举一个小例子,找出数组中重复次数最多的元素并打印,能否给出更优的方案
  1. public class Problem_3 {   
  2.        
  3.     //先快速排序后循环查找    O( n*log2(n) + n )   
  4.     public static void find1(int[] arr){   
  5.            
  6.         QuickSort.sort(arr);   
  7.            
  8.            
  9.         int max = arr[0];   
  10.         int pre=1;   
  11.         int now=1;   
  12.            
  13.         for(int i=0;i<(arr.length-1);i++){   
  14.                
  15.             if(arr[i]==arr[i+1])   
  16.                 now++;   
  17.             else {   
  18.                 if(now>=pre){   
  19.                     pre=now;   
  20.                     now=1;   
  21.                     max=arr[i];   
  22.                 }      
  23.             }   
  24.         }   
  25.            
  26.            
  27.            
  28.     }   
  29.        
  30.     //嵌套循环查找   O(n*n)   
  31.     public static void find2(int[] arr){   
  32.            
  33.   
  34.         int pre=0;   
  35.         int max=arr[0];   
  36.            
  37.         for(int i=0;i
  38.             int now=0;   
  39.             for(int j=0;j
  40.                    
  41.                 if(arr[i]==arr[j]) {   
  42.                     now++;     
  43.                 }                  
  44.             }   
  45.                
  46.             if(now>=pre){               
  47.                 max=arr[i];   
  48.                 pre=now;               
  49.             }   
  50.                
  51.                        
  52.         }   
  53.            
  54.        
  55.            
  56.     }   
  57.        
  58.     //通过 Hash 方式   
  59.     public static void find3(int[] arr){   
  60.         HashMap hm=new HashMap();   
  61.         for(int i=0;i
  62.             if(hm.containsKey(arr[i])) {   
  63.                 int count=hm.get(arr[i]);   
  64.                 hm.put(arr[i], ++count);   
  65.                 
  66.             }else{   
  67.                 hm.put(arr[i],1);   
  68.             }   
  69.         }   
  70.            
  71.         Iterator> it=hm.entrySet().iterator();   
  72.         int pre=0;   
  73.         int max=arr[0];   
  74.         while(it.hasNext()) {   
  75.             Entry en=it.next();   
  76.             int key=en.getKey();   
  77.             int val=en.getValue();   
  78.             if(val>pre){    
  79.                 pre=val;   
  80.                 max=key;   
  81.             }   
  82.                
  83.         }   
  84.            
  85.        
  86.            
  87.     }   
  88.     public static  void main(String args[]){   
  89.   
  90.         //数据量800 重复元素多,查找时候分别是:  46  3680  195   
  91.         int arr2[]={0,1,2,        .....          
  92.                 ,0,1,2,3,6,7,8,9};   
  93.            
  94.         //数据量800 重复元素少,查找时间分别是     82  3727  360   
  95.         int arr[]={0,0,0,11,12,13,14,5,6    ......        
  96.                         ,51,52,53,,728,29,730,731,3,794,95,796,797,798,799};   
  97.            
  98.   
  99.            
  100.         long start,end;   
  101.                
  102.         start=System.currentTimeMillis();   
  103.         for(int i=0;i<1000;i++) find1(arr);   
  104.         end=System.currentTimeMillis();   
  105.         System.out.println(end-start);   
  106.            
  107.         start=System.currentTimeMillis();   
  108.         for(int i=0;i<1000;i++) find2(arr);   
  109.         end=System.currentTimeMillis();   
  110.         System.out.println(end-start);   
  111.            
  112.            
  113.         start=System.currentTimeMillis();   
  114.         for(int i=0;i<1000;i++) find3(arr);   
  115.         end=System.currentTimeMillis();   
  116.         System.out.println(end-start);   
  117.            
  118.     }   
  119. }  

大家都知道在C++的STL中map是使用树来做查找算法,而hash_map使用hash表来排列配对,是使用关键字来计算表位置。那使用起来他们的差别主要是什么呢?对于性能差别是什么,适合什么情况下应用呢?于是我对它们进行了一些测试,并记录了测试数据供大家分享。
    测试的内容主要是map和hash_map的添加、删除、查找和遍历操作,首先进行了几组测试,分别是10万次、30万次,时间单位均为毫秒,具体的性能对照如下:
  hash_map(10万) map(10万) hash_map(20万) map(20万) hash_map(30万) map(30万)
添加 93   47  156   94  203   172
遍历 16   15  16   16  16   15
查找    32   31  31   32
删除 8422   32  33765   63  76016   78
    通过上面的数据比较,我们很容易发现hash_map的添加和删除操作比map要慢,尤其是删除操作hash_map比map可能慢1000倍;从而得到结论是删除和插入操作较多的情况下,map比hash_map的性能更好,添加和删除的数据量越大越明显。但我们使用map、hash_map一般都用于查找和遍历较多,而且上述测试数据也不能反映出这两方面的性能差距,于是继续对查找和遍历进行了性能测试,得到具体数据如下,时间单位仍为毫秒:
 hash_map(100万) map(100万) hash_map(200万) map(200万) hash_map(300万) map(300万)
遍历 94   31  203   32  297   47
查找 94   234  188   531  281   875
    通过上面的测试数据可以得出结论是map的遍历性能高于hash_map,而查找性能则相反,hash_map比map要好,数据量越大查找次数越多,表现就越好。
    两大组测试完毕,整体结论也可以得出:一般应用情况下,我们保存的数据不超过100万份,查找的频繁程度不高情况下使用map性能比较好;而保存的数据较多时(超过100万),查找频繁时使用hash_map的性能就高于map了。

测试环境具体如下:
操作系统:Windows XP Professional (5.1, Build 2600) Service Pack 3 (2600.xpsp_sp3_gdr.080814-1236)
编译环境:Microsoft Visual C++ 2005   55603-007-4000003-41525
处理器:Intel(R) Core(TM)2 Duo CPU     P8600  @ 2.40GHz (2 CPUs)
内存:2044MB RAM,
     另外,整个测试仅使用物理内存,而没有虚拟内存,使用Release版本直接在控制台中运行,而没有在IDE中运行,避免影响性能;且对于较短时间计时,少于20毫秒以下可能不准确。

  1.map介绍  使用map得包含map类所在的头文件:    #include //注意,STL头文件没有扩展名.h

1.1 map的构造

  Template   map(); // 默认构造函数  默认为升序即map>,如果想改成降序,则map>,  map(const map& m) // 拷贝构造函数   map(iterator begin, iterator end ); //区间构造函数   map(iterator begin, iterator end, const traits& _compare) //带比较谓词的构造函数   map(iterator begin, iterator end, const traits& _compare, const allocator& all) //带分配器

1.2 map定义

  1.2.1map的基本定义   map对象是模板类,需要关键字和存储对象两个模板参数:   std:map personnel;   这样就定义了一个用int作为索引,并拥有相关联的指向string的指针.   为了使用方便,可以对模板类进行一下类型定义:   typedef map UDT_MAP_INT_CSTRING;   UDT_MAP_INT_CSTRING enumMap; //后面会依此例说明   1.2.2 map的嵌套定义   map > //注意:最后两个>之间有个空格   map支持下标运算符operator[],用访问普通数组的方式来访问map;不过下标为map的键,在multimap中一个键可以对应多个不同的值。

2.map的方法

2.1 在map中插入元素

  三种插入方式:   2.1.1用insert方法插入pair对象:    enumMap.insert(pair(1, “One”));   2.1.2 用insert方法插入type_value对象:    enumMap.insert(map::value_type (1, “One”));

2.2 查找并获取map中元素

  2.2.1下标操作符给出了获得一个值的最简单方法:  CString tmp = enumMap[2];  但是,只有当map中有这个键的实例时才对,否则会自动插入一个实例,值为初始化值。  2.2.2我们可以使用find()和count()方法来发现一个键是否存在  查找map中是否包含某个关键字条目用find()方法,传入的参数是要查找的key,在这里需要提到的是begin()和end()两个成员,分别代表map对象中第一个条目和最后一个条目,这两个数据的类型是iterator.  int nFindKey = 2; //要查找的Key  //定义一个条目变量(实际是指针)  UDT_MAP_INT_CSTRING::iterator it= enumMap.find(nFindKey);  if(it == enumMap.end()) {  cout<<"没找到"<first 关键字(key)  iterator->second 存储的数据(value)

2.3 从map中删除元素

  2.3.1移除某个map中某个条目用erase()  该成员方法的定义如下:  1.iterator erase(iterator it); //通过一个条目对象删除  2.iterator erase(iterator first, iterator last); //删除一个范围  3.size_type erase(const Key& key); //通过关键字删除  2.3.2清除所有的元素clear()  clear()就相当于 enumMap.erase(enumMap.begin(), enumMap.end());

2.4 map中swap的用法

  map中的swap不是一个容器中的元素交换,而是两个容器交换;  For example:  #include   #include   using namespace std;  int main( )  {  map m1, m2, m3;  map ::iterator m1_Iter;  m1.insert ( pair ( 1, 10 ) );  m1.insert ( pair ( 2, 20 ) );  m1.insert ( pair ( 3, 30 ) );  m2.insert ( pair ( 10, 100 ) );  m2.insert ( pair ( 20, 200 ) );  m3.insert ( pair ( 30, 300 ) );  cout << "The original map m1 is:";  for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )  cout << " " << m1_Iter->second;  cout << "." << endl;  // This is the member function version of swap  //m2 is said to be the argument map; m1 the target map  m1.swap( m2 );  cout << "After swapping with m2, map m1 is:";  for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )  cout << " " << m1_Iter -> second;  cout << "." << endl;  cout << "After swapping with m2, map m2 is:";  for ( m1_Iter = m2.begin( ); m1_Iter != m2.end( ); m1_Iter++ )  cout << " " << m1_Iter -> second;  cout << "." << endl;  // This is the specialized template version of swap  swap( m1, m3 );  cout << "After swapping with m3, map m1 is:";  for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )  cout << " " << m1_Iter -> second;  cout << "." << endl;  }

2.5 map的sort问题

  Map中的元素是自动按key升序排序,所以不能对map用sort函数:  For example:  #include   #include   using namespace std;  int main( )  {  map m1;  map ::iterator m1_Iter;  m1.insert ( pair ( 1, 20 ) );  m1.insert ( pair ( 4, 40 ) );  m1.insert ( pair ( 3, 60 ) );  m1.insert ( pair ( 2, 50 ) );  m1.insert ( pair ( 6, 40 ) );  m1.insert ( pair ( 7, 30 ) );  cout << "The original map m1 is:"<first<<" "<second<2.6 map的基本操作函数  C++ Maps是一种关联式容器,包含“关键字/值”对  begin() 返回指向map头部的迭代器  clear() 删除所有元素  count() 返回指定元素出现的次数  empty() 如果map为空则返回true  end() 返回指向map末尾的迭代器  equal_range() 返回特殊条目的迭代器对  erase() 删除一个元素  find() 查找一个元素  get_allocator() 返回map的配置器  insert() 插入元素  key_comp() 返回比较元素key的函数  lower_bound() 返回键值>=给定元素的第一个位置  max_size() 返回可以容纳的最大元素个数  rbegin() 返回一个指向map尾部的逆向迭代器  rend() 返回一个指向map头部的逆向迭代器  size() 返回map中元素的个数  swap() 交换两个map  upper_bound() 返回键值>给定元素的第一个位置  value_comp() 返回比较元素value的函数

编辑本段3.例子

  #include   #include   using namespace std;  int main(void)  {  map > map1;  map >::iterator mapIter;  //char 是键的类型,int是值的类型  //下面是初始化,与数组类似  //也可以用map1.insert(map >::value_type(''c'',3));  map1[''c'']=3;  map1[''d'']=4;  map1[''a'']=1;  map1[''b'']=2;  for(mapIter=map1.begin();mapIter!=map1.end();++mapIter)  cout<<" "<<(*mapIter).first<<": "<<(*mapIter).second;  //first对应定义中的char键,second对应定义中的int值  //检索对应于d键的值是这样做的:  map >::const_iterator ptr;  ptr=map1.find(''d'');  cout<<''\n''<<" "<<(*ptr).first<<" 键对应于值:"<<(*ptr).second;  cin.get();  return 0;  }  从以上例程中,我们可以看到map对象的行为和一般数组的行为类似。Map允许两个或多个值使用比较操作符。下面我们再看看multimap:  #include   #include   #include   using namespace std;  int main(void)  {  multimap >mulmap;  multimap >::iterator p;  //初始化多重映射mulmap:  typedef multimap >::value_type vt;  typedef string s;  mulmap.insert(vt(s("Tom "),s("is a student")));  mulmap.insert(vt(s("Tom "),s("is a boy")));  mulmap.insert(vt(s("Tom "),s("is a bad boy of blue!")));  mulmap.insert(vt(s("Jerry "),s("is a student")));  mulmap.insert(vt(s("Jerry "),s("is a beatutiful girl")));  mulmap.insert(vt(s("DJ "),s("is a student")));  //输出初始化以后的多重映射mulmap:  for(p=mulmap.begin();p!=mulmap.end();++p)  cout<<(*p).first<<(*p).second<{
public:
 CTPMapGuidToPtr(void);
 ~CTPMapGuidToPtr(void);
public:  void* GetAt(GUID guidGet);
 void* operator[](GUID guidGet);
 void SetAt(GUID guidGet, void* newValue);
 BOOL RemoveAt(GUID guidGet);
 void RemoveAll();
 void ReSetCatalog();
}; CTPMapGuidToPtr::CTPMapGuidToPtr(void)
{
}CTPMapGuidToPtr::~CTPMapGuidToPtr(void)
{
} void* CTPMapGuidToPtr::GetAt(GUID guidGet){         unsigned short *pUuidString = NULL;         RPC_STATUS  ret = UuidToString(&guidGet,&pUuidString);//Uuid为&Guid         if(pUuidString == NULL)  return NULL;         void           *pVoid       = NULL;         CString      sGuid  = (LPTSTR)pUuidString;         RpcStringFree((unsigned short**) &pUuidString );          if(CMapStringToPtr::Lookup(sGuid,pVoid)) return pVoid;         else return NULL;} void* CTPMapGuidToPtr::operator[](GUID guidGet)
{
       unsigned short *pUuidString = NULL;
       RPC_STATUS ret = UuidToString(&guidGet, &pUuidString);
       if(pUuidString == NULL)  return NULL;
       void           *pVoid       = NULL;
       CString         sGuid       = (LPTSTR)pUuidString;
       RpcStringFree((unsigned short**) &pUuidString ); 
       if(CMapStringToPtr::Lookup(sGuid,pVoid)) return pVoid;
       else return NULL;
} void CTPMapGuidToPtr::SetAt(GUID guidGet, void* newValue)
{
    unsigned short *pUuidString = NULL;
    RPC_STATUS ret = UuidToString(&guidGet, &pUuidString);
    if(pUuidString == NULL)  return ; 
    CString         sGuid       = (LPTSTR)pUuidString;
    RpcStringFree((unsigned short**) &pUuidString ); 
    CMapStringToPtr::SetAt(sGuid,newValue);
} BOOL CTPMapGuidToPtr::RemoveAt(GUID guidGet)
{
    unsigned short *pUuidString = NULL;
    RPC_STATUS ret = UuidToString(&guidGet, &pUuidString);
    if(pUuidString == NULL)  return NULL; 
    CString         sGuid       = (LPTSTR)pUuidString;
    RpcStringFree((unsigned short**) &pUuidString );
    CTPResObject   *pResObject  = NULL;
    if(!CMapStringToPtr::Lookup(sGuid,(void *&)pResObject)) return  FALSE;
    if(pResObject ->m_dwBaseType == TP_TYPE_CLIP)               delete (CTPResClip *)pResObject;
   else if(pResObject ->m_dwBaseType == TP_TYPE_CLIPCACHE)     delete (CTPResClipCache *)pResObject;
   else if(pResObject ->m_dwBaseType == TP_TYPE_PROGRAM)       delete (CTPResProgram *)pResObject;
   else if(pResObject ->m_dwBaseType == TP_TYPE_PROGRAMCACHE)  delete (CTPResProgramCache *)pResObject;
   else if(pResObject ->m_dwBaseType == TP_TYPE_TEMPALTE)      delete (CTPResTemplate *)pResObject;
   else if(pResObject ->m_dwBaseType == TP_TYPE_TEMPALTECACHE) delete (CTPResTemplateCache *)pResObject;
   else  delete pResObject;
   return CMapStringToPtr::RemoveKey(sGuid); 
}
void CTPMapGuidToPtr::RemoveAll()
{
    CString         sGuid;
    CTPResObject   *pResObject  = NULL;
    POSITION posGet = CMapStringToPtr::GetStartPosition();
    while(posGet)
    {
        CMapStringToPtr ::GetNextAssoc(posGet,sGuid,(void *&)pResObject);
        if(pResObject == NULL)  continue;
        if(pResObject ->m_dwBaseType == TP_TYPE_CLIP)               delete (CTPResClip *)pResObject;
        else if(pResObject ->m_dwBaseType == TP_TYPE_CLIPCACHE)     delete (CTPResClipCache *)pResObject;
        else if(pResObject ->m_dwBaseType == TP_TYPE_PROGRAM)       delete (CTPResProgram *)pResObject;
        else if(pResObject ->m_dwBaseType == TP_TYPE_PROGRAMCACHE)  delete (CTPResProgramCache *)pResObject;
        else if(pResObject ->m_dwBaseType == TP_TYPE_TEMPALTE)      delete (CTPResTemplate *)pResObject;
        else if(pResObject ->m_dwBaseType == TP_TYPE_TEMPALTECACHE) delete (CTPResTemplateCache *)pResObject;
        else  delete pResObject;
    }
    CMapStringToPtr ::RemoveAll();
}
void  CTPMapGuidToPtr::ReSetCatalog()
{
    CString     sGuid;
    CTPResBase *pBase = NULL;
    POSITION posGet = CMapStringToPtr::GetStartPosition();
    while(posGet)
    {
        CMapStringToPtr ::GetNextAssoc(posGet,sGuid,(void *&)pBase);
        if(pBase) pBase ->m_pCatalog = NULL;  
    }
}   void   CTPResCache::ClearResCache(TP_RES_TYPE eResType)
{
      if(eResType == TP_RES_ALL)
    { 
           ClearResCache(TP_RES_CLIP);
           ClearResCache(TP_RES_HIDECLIP);
           ClearResCache(TP_RES_ALLPROGRAM);
           ClearResCache(TP_RES_ALLTEMPLATE);
           return ;
    }
    if(m_bLockCache) return;
    //防止频繁 操作
    DWORD dwTickCount      = GetTickCount();
    if(dwTickCount     {
        m_dwTickCount = dwTickCount;
        return;
    }
    m_dwTickCount = dwTickCount;    if(eResType & TP_RES_CLIP)
    {
        if((DWORD)m_aClipCache.GetSize()        POSITION posGet;CString sGuid;CTPResClipCache *pClipCache = NULL;
        posGet = m_aClipCache.GetStartPosition();
        while (posGet) 
       {
            m_aClipCache.GetNextAssoc(posGet,sGuid,(void *&)pClipCache);
            if(pClipCache->GetUsedCount()<=0) m_aClipCache.RemoveAt(pClipCache ->m_guidClip);
        }
        if((DWORD)m_aClipCache.GetSize()        SYSTEMTIME  tmCur;GetLocalTime(&tmCur);        posGet = m_aClipCache.GetStartPosition();
        while (posGet) 
        {
               m_aClipCache.GetNextAssoc(posGet,sGuid,(void *&)pClipCache);
               if(pClipCache->GetLockCount(1) > 0) continue; // Read and Write Mode should not release
               if(_tmcount(&tmCur) - _tmcount(&pClipCache->m_tmLastUsed) >50)
                   pClipCache ->ReleaseData();   
        }
    }
}  CTPResObject *CTPResCache::GetRes(GUID guidRes,GUID guidDBType,TP_RES_TYPE eResType,TP_RESLOCK_FLAG eLockType)
{
       if(!GetResLockSate(guidRes,guidDBType,eResType,eLockType)) return NULL;
       TPMutex muteLock(_L("GetRes"));
       if(eResType & TP_RES_CLIP)
       {
              CTPResClip *pResClip = new CTPResClip();              pResClip ->m_eResLock    = eLockType;
              pResClip ->m_pResCache   = this; 
              pResClip ->m_pClipCache  = NULL;
 
              pResClip ->m_pClipCache = (CTPResClipCache *)m_aClipCache.GetAt(guidRes);              if(pResClip ->m_pClipCache == NULL) 
              {
                  CTPResClipCache *pClipCache = new CTPResClipCache();
                  pClipCache ->m_guidClip    = guidRes;
                  pClipCache ->m_pResCache   = this; 
                  pClipCache ->m_pCatalog    = NULL;
                  m_aClipCache.SetAt(guidRes,pClipCache);
                  pResClip ->m_pClipCache = pClipCache;
              }
              pResClip ->m_pClipCache ->LockRes(pResClip);
              ClearResCache(TP_RES_CLIP);               return pResClip;
       }} //CMap为Hash Mapvoid TP_GetUniqueGuidCatalog(CGuidArray &aGuidCatalog,GUID guidDBType)
{
 int iGuidCatalogNum = aGuidCatalog.GetSize();
 if(iGuidCatalogNum <= 0) return; CMap aGuidMap(iGuidCatalogNum);
 CStringArray aAllFile;
 CGuidArray   aGuidNode;
 for(int i = 0 ; i< aGuidCatalog.GetSize() ; i++)
 {
  HANDLE  hCatalog = NULL;
  CString sPath;   
  TPCatalogData stuCatalog;
  g_pClipManageInterface->stuTreeInterface.TP_GetCatalog(guidDBType,GUID_NULL,aGuidCatalog[i],hCatalog);
  g_pClipManageInterface->stuTreeInterface.TP_GetCatalogInfo(hCatalog, &stuCatalog);
  sPath = g_pClipManageInterface->stuTreeInterface.TP_GetCatalogFullPath(hCatalog);
  if(!sPath.IsEmpty()) 
  {
   aAllFile.Add(sPath);
   aGuidNode.Add(stuCatalog.guidNode);
   aGuidMap.SetAt(sPath, aGuidCatalog[i]);
  }
 } for(INT i = 0; i < aAllFile.GetSize(); i++)
 {
  for(INT j = 0; j < aAllFile.GetSize(); j++)
  {
   if(i != j  && aAllFile[i].Find(aAllFile[j]) >= 0 && aGuidNode[i] != aGuidNode[j])
    aGuidMap.RemoveKey(aAllFile[i]);
  }
 } aGuidCatalog.RemoveAll();
 POSITION pos = aGuidMap.GetStartPosition();
 while(NULL != pos)
 {
  CString sKey;
  GUID guidCat = GUID_NULL;
  aGuidMap.GetNextAssoc(pos, sKey, guidCat);
  if(GUID_NULL != guidCat) aGuidCatalog.Add(guidCat); }
} 本来不想讨论这类问题,不过今天比较闲,说几句
一,iostream的getline系列功能,基本上都是小儿科用途的,getline不做硬盘缓冲优化,不做内存优化,同时还要挨个字符检查是否是换行,这对于读取大量数据本来就是不适合的。这些功能一般只用在小规模测试,以及少量数据的偶然读取才使用。真正需要大量数据处理的情况,一定要整个文件载入内存,然后加以适当的分割。

二,对于不断增长的容器,vector如果不能事先reserve的话,效率绝对没法保证,因为每次增长都要进行批量的数据拷贝,而vector的push_back本身也带来一次拷贝构造,对比较大的类型来说,效率基本是不行的。这里可以考虑用deque。
如果非要使用vector,则应该首先reserve,并且尽量存指针而不是对象(如果对象很大的话)。

三,vc自带的map不是hash_map而是RB-Tree,在构造开销上本来就比较大,并且map的效率主要体现在查找而不是构造。用只有两个数据的map测试效率简直就是弱智行为,这种数据量用两个单独的变量来分别比较绝对是最快的算法。

四,当string长度比较短的时候,用固定长度的数组或者vector来代替string是有效的方法,因为string的各种操作都要考虑'\0'结尾,在构造和拷贝构造等效率上肯定比vector或者普通数组低。(btw:当string长度完全固定且只有4字节,如帖子中所说,仍然坚持用std::string或者CString一类来处理,而又要高效的也可以认为是弱智行为,这时候有效率的做法是用4个字节构造一个DWORD作为键值)

五,list,选择的list就选择了缺乏效率,如果list内部再存储对象而不是指针,频繁的push_back纯粹就是折腾内存,完全没有意义的行为。既然知道要存这么多对象,完全可以用其他容器建立一个pool然后用list操作其引用,既避免了list存储的对象过大导致的效率开销,又避免了内存的频繁分配和释放导致的额外开销。

六,以上这些帖子的内容基本上都是使用不当或者设计上的缺陷,和stl/mfc根本没有任何关系,而根据这些错误的使用就得出各种结论也是毫无意义的。讨论这些问题本身就是没有意义的行为,这些东西应该在大学数据结构和算法的课程中就学过了,如果那个大学称得上是“大学”的话。