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后的迭代器会失效).
为什么要选择合适的排序函数?可能你并不关心效率(这里的效率指的是程序运行时间), 或者说你的数据量很小, 因此你觉得随便用哪个函数都无关紧要。
其实不然,即使你不关心效率,如果你选择合适的排序函数,你会让你的代码更容易让人明白,你会让你的代码更有扩充性,逐渐养成一个良好的习惯,很重要吧 。
如果你以前有用过C语言中的qsort, 想知道qsort和他们的比较,那我告诉你,qsort和sort是一样的,因为他们采用的都是快速排序。从效率上看,以下几种sort算法的是一个排序,效率由高到低(耗时由小变大):
- partion
- stable_partition
- nth_element
- partial_sort
- sort
- 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的排序效果,你必须间接使用。正如上面介绍的有几种方式可以选择。