2010.11.14 关于map的问题

之前没用过stl的map,这次遇到了一个问题比较麻烦。

map会自动按照关键字,进行排序。如果需要按照输入顺序,输出所有元素,那么你会发现,其中的顺序已经乱了。有如下方法可以尝试(注意没有解决):

方法一:http://blog.csdn.net/huskyxufei/archive/2010/06/11/5665188.aspx

 

让我们来看看stl中map的 声明形式    map<Key, Data, Compare, Alloc>

注意第三个参数

Compare : The key comparison function, a Strict Weak Ordering whose argument type is key_type; it returns true if its first argument is less than its second argument, and false otherwise. This is also defined as map::key_compare.

其作用就是比较Key的大小,按照一定的顺序确定map节点的顺序,我们当然就可以定制这个函数对象以实现我们想要的的排序规则。

好了,废话说了不少,我的做法是

template<class T>
struct DisableCompare :public std::binary_function<T,T,bool>
{
    bool operator()(T lhs,T rhs)  const
    {
        return true;
     }
};

这样来使用定制化的map :

 std::map<double,int,DisableCompare<double> > sMap;
 sMap[10.9] = 1;
 sMap[3.5]  =  2;
 sMap[30.0] = 3;
 sMap[2.4]  =  4;

就可以保持数据插入时候的顺序了

 我自己编码试了试,

 

using namespace std;
#include "map"
#include "string"

template<class T>
struct DisableCompare :public std::binary_function<T,T,bool>
{
 bool operator()(T lhs,T rhs)  const
 {
  return true;
 }
};

 

int _tmain(int argc, _TCHAR* argv[])
{
    map<int,int,DisableCompare<int>> m_map;
 //m_map.insert(map<int,int>::value_type(1,1));
 m_map.insert(make_pair(5,1));
 m_map.insert(make_pair(3,1));
 m_map.insert(make_pair(4,1));
 m_map.insert(make_pair(1,1));
 
 map<int,int,DisableCompare<int>>::iterator iter=m_map.begin();
 for (;iter!=m_map.end();iter++)
 {
  cout<<""<<iter->first<<endl;
 }


 //注意此处必须引入头文件#include "string"
 map<string,string> m_map2;
 m_map2.insert(pair<string,string>("z","aa"));

 m_map2.insert(make_pair("f","bb"));
 m_map2.insert(make_pair("g","bb"));
 m_map2.insert(make_pair("e","bb"));


    map<string,string>::iterator iter2=m_map2.begin();
 for (;iter2!=m_map2.end();iter2++)
 {
  cout<<""<<iter2->first<<endl;
 }

 int v1;
 cin>>v1;
 return 0;
}

确实取消了排序,不过map中元素的排序刚好和插入的顺序相反。这个需要注意。

思考一下,stl中的map用的是红黑树,也就是数据结构中平衡二叉树,要求每个节点的左子树和右子树,深度差不能超过2。这样才能保证map映射的效率。这样看来,如果非要取消map的排序功能,其实背离了map原有的效率,就不应该用map,应该考虑其它容器。

那么修改struct DisableCompare :public std::binary_function<T,T,bool>
{
 bool operator()(T lhs,T rhs)  const
 {
  return true;
 }
};中的true为false,可以吗?可以自己试试,答案是只能插入第一个元素,后面的无法写入。需要理解该函数到底是怎么发挥作用的。
 

方法二、用stl的sort排序?

 

 

STL中标准容器主要vector, list, deque, string, set, multiset, map, multimay, 其中set, multiset, map, multimap都是以树结构的方式存储其元素详细内容请参看:学习STL map, STL set之数据结构基础. 因此在这些容器中,元素一直是有序的。

这些容器的迭代器类型并不是随机型迭代器,因此,上述的那些排序函数,对于这些容器是不可用的。上述sort函数对于下列容器是可用的:

  • vector
  • string
  • deque

如果你自己定义的容器也支持随机型迭代器,那么使用排序算法是没有任何问题的。

对于list容器,list自带一个sort成员函数list::sort(). 它和算法函数中的sort差不多,但是list::sort是基于指针的方式排序,也就是说,所有的数据移动和比较都是此用指针的方式实现,因此排序后的迭代器一直保持有效(vector中sort后的迭代器会失效).

3 选择合适的排序函数


为什么要选择合适的排序函数?可能你并不关心效率(这里的效率指的是程序运行时间), 或者说你的数据量很小, 因此你觉得随便用哪个函数都无关紧要。

其实不然,即使你不关心效率,如果你选择合适的排序函数,你会让你的代码更容易让人明白,你会让你的代码更有扩充性,逐渐养成一个良好的习惯,很重要吧 。

如果你以前有用过C语言中的qsort, 想知道qsort和他们的比较,那我告诉你,qsort和sort是一样的,因为他们采用的都是快速排序。从效率上看,以下几种sort算法的是一个排序,效率由高到低(耗时由小变大):

  1. partion
  2. stable_partition
  3. nth_element
  4. partial_sort
  5. sort
  6. stable_sort

记得,以前翻译过Effective STL的文章,其中对如何选择排序函数总结的很好:

  • 若需对vector, string, deque, 或 array容器进行全排序,你可选择sort或stable_sort;
  • 若只需对vector, string, deque, 或 array容器中取得top n的元素,部分排序partial_sort是首选.
  • 若对于vector, string, deque, 或array容器,你需要找到第n个位置的元素或者你需要得到top n且不关系top n中的内部顺序,nth_element是最理想的;
  • 若你需要从标准序列容器或者array中把满足某个条件或者不满足某个条件的元素分开,你最好使用partition或stable_partition;
  • 若使用的list容器,你可以直接使用partition和stable_partition算法,你可以使用list::sort代替sort和stable_sort排序。若你需要得到partial_sort或nth_element的排序效果,你必须间接使用。正如上面介绍的有几种方式可以选择。

 

posted @ 2010-11-14 10:58  pjh123  阅读(245)  评论(0编辑  收藏  举报