一、关联性容器(map vs TreeMap):

  我们在用Java进行编程时经常会用到Map这样的容器接口,而它的具体实现类一般来自于TreeMap和HashMap,前者提供了有序性,而后者则在存取效率方面有着一定的优势。相比于Java,C++的STL也提供了map容器,其功能等同于Java中的TreeMap,至于HashMap,它并没有进入C++标准模板库。而幸运的是,现有的主流C++编译器供应商均提供了标准模板库的扩展包,并在该扩展包中实现了hash_map容器类,其接口标准和STL中的容器基本一致。

  在本条目中我们将主要列举TreeMap(Java)和map(C++)在设计上的主要差别,以及关键功能实现上的明显差异,并基于此给出在实际代码移植过程中该如何应对这些差异所带来的诸多问题:

  1、插入相同键时两种容器表现不同,其中Java的TreeMap会将后插入的键值对直接覆盖容器中已经存在的键值对,而C++中的map容器则恰恰相反,一旦容器中该键已经存在,那么新插入的键值对将不会被存入该容器对象中,见如下Java代码及输出结果。

public class MyTest {
         private static void testGet() {
             TreeMap<String,String> tm = new TreeMap<String,String>();
             tm.put("Hello", "World");
             if (tm.get("Hello1") == null)
                 System.out.println("Hello1 is NOT found.");
         }
   
         public static void main(String[] args) {
             TreeMap<Integer,Integer> tm = new TreeMap<Integer,Integer>();
             tm.put(5, 10);
             tm.put(5, 20);
             Set<Entry<Integer,Integer>> entries = tm.entrySet();
             Iterator<Entry<Integer,Integer>> it = entries.iterator();
           
             while (it.hasNext()) {
                 Entry<Integer,Integer> e = it.next();
                 System.out.printf("key = %d, value = %d ",e.getKey().intValue(),e.getValue().intValue());
             }
         }
     }
     //The count of the TreeMap is 1
     //key = 5, value = 20

  见如下C++代码及输出结果。

using namespace std;
     int main()
     {
         map<int,int> m;
         m.insert(make_pair(5,10));
         m.insert(make_pair(5,20));
         printf("The count of the map is %d. ",m.size());
         map<int,int>::iterator it = m.begin();
         for (; it != m.end(); ++it) {
             printf("key = %d, value = %d ",(*it).first,(*it).second);
         }
         return 0;
     }
     //The count of the map is 1
     //key = 5, value = 10

  从以上结果便可以清晰的看出二者之间的差别,那么我们又该如何修改C++的代码,以使其和原有的Java代码逻辑保持一致呢?现在答案已经非常清楚了,我们只需在插入前先行判断该键是否存在,如果存在则删除已有键值对,之后再将新键值对插入到该容器对象中,或者通过已有键的迭代器访问该键的值,并赋予新值。至于该使用哪种方式,则需要依据实际情况而定,通常而言,第一种方法可以应对所有场景,但是效率相比于第二种方法要略低一些。见如下修改后的C++代码:

using namespace std;
     int main()
     {
         map<int,int> m;
         m.insert(make_pair(5,10));
         map<int,int>::iterator it = m.find(5);
       
         if (it != m.end())
             m.erase(it);
         m.insert(make_pair(5,20));
         //或实现为以下方式
         //if (it != m.end())
         //    it->second = 20;
         //else
         //    m.insert(make_pair(5,20));
       
         printf("The count of the map is %d. ",m.size());
         it = m.begin();
         for (; it != m.end(); ++it)
             printf("key = %d, value = %d ",(*it).first,(*it).second);
         return 0;
     }
     //The count of the map is 1
     //key = 5, value = 10