由2个值组合成key的STL map排序问题

时间:2022-06-10 19:17:26

某网友问:“map中怎么设置多个key值进行排序?”

 

在C++中,map是典型的关联容器或者叫映射容器(associative container),其中的每一个元素都是由key-value这样成对出现的内容组成的,比如学号和学生之类具有一一对应关系的情形,学号可以作为key,学生对象可以作为key所对应的value。很显然这种情况下的key只有一个值,但是,在实际工作中,我们可能会经常需要使用多个值组合起来作为key的情况,比如我们要按照学生的视力和身高进行排序,以决定学生的座位排在前面还是后面,而且还是假定要用map来解决这样的问题(当然,这样的问题有很多其它的解决办法),那应该怎么办呢?

 

(1)  单值作为key的情形

我们知道map在缺省状态下,其数据是按照key的升序进行排列的。假定我们有一个Student类,声明如下:

class Student
{
private:
         int id;                  // 学号
         string name;             // 姓名
         float eyesight;          // 视力
         float height;            // 身高
         float chinese;           // 语文成绩
         float english;           // 英文成绩
         float math;              // 数学成绩
public:
         Student(int id, string name,floateyesight, float height,float chinese, float english,float math)
         {
                   this->id = id;
                   this->name = name;
                   this->eyesight = eyesight;
                   this->height = height;
                   this->chinese = chinese;
                   this->english = english;
                   this->math = math;
         }
 
         int get_id()
         {
                   return id;
         }
 
         string get_name()
         {
                   return name;
         }
 
         float get_eyesight()
         {
                   return eyesight;
         }
 
         float get_height()
         {
                   return height;
         }
 
         float get_chinese()
         {
                   return chinese;
         }
 
         float get_english()
         {
                   return english;
         }
 
         float get_math()
         {
                   return math;
         }
};
 

那么下面的程序:

int main(int argc,char**argv)
{
       map<int, Student> stu_map;    // int作为key的类型,Student作为value的类型
       stu_map.insert(make_pair(4,Student(4, "Dudley",1.1f, 170.2f, 90.5f, 89.5f, 93.0)));
       stu_map.insert(make_pair(3,Student(3, "Chris", 1.1f, 163.4f, 93.5f,90.0f, 83.5f)));
       stu_map.insert(make_pair(2,Student(2, "Bob", 1.5f, 166.6f, 86.0f,98.5f, 85.0f)));
       stu_map.insert(make_pair(1,Student(1, "Andrew", 1.5f, 173.2f, 98.5f,100.0f, 100.f)));
 
       map<int, Student>::iterator iter;
       for(iter = stu_map.begin(); iter != stu_map.end();++iter)
       {
              cout<< iter->first << "\t"<< iter->second.get_name() << endl;
       }
 
       return 0;
}
 

就会按照学号的升序给出输出:

1          Andrew

2          Bob

3          Chris

4          Dudley

这是缺省的情形,如果要将学生的姓名按照学号的降序输出,那么仅需将上面main函数中的

map<int,Student> stu_map;改为

map<int,Student, greater<int> > stu_map;

以及

map<int,Student>::iterator iter;改为

map<int,Student, greater<int> >::iteratoriter;

即可。

 

其实,map<int,Student> stu_map;这是一种缺省的情况,它和

map<int,Student, less<int> > stu_map;是一样的。

 

(2) 多值组合作为key的情形

现在,我们来看看多个值组合起来作为key的情况,为此,我们需要为key定义一个类,如下:

class key
{
public:
       float eyesight;
       float height;
 
       key(float x, floaty):eyesight(x), height(y)
       {
       }
 
       friend bool operator < (constkey&,const key&);
};
 
bool operator < (constkey& key1,const key& key2)
{
       // 按eyesight升序 + height升序排列
       if(key1.eyesight != key2.eyesight)      
              return (key1.eyesight < key2.eyesight);
       else
              return (key1.height < key2.height);
      
       // 按eyesight降序 + height降序排列
       //if(key1.eyesight != key2.eyesight)    
       //     return(key1.eyesight > key2.eyesight);
       //else                                 
       //     return(key1.height > key2.height);
 
       // 按eyesight升序 + height降序排列
       //if(key1.eyesight != key2.eyesight)    
       //     return(key1.eyesight < key2.eyesight);
       //else                                 
       //     return(key1.height > key2.height);
 
       // 按eyesight降序 + height升序排列
       //if(key1.eyesight != key2.eyesight)    
       //     return(key1.eyesight > key2.eyesight);
       //else                                 
       //     return(key1.height < key2.height);
}
 

再修改main函数如下:

int main(int argc,char**argv)
{
       map<key,Student> stu_map;
 
       Studentstu4(4, "Dudley",1.1f, 170.2f, 90.5f, 89.5f, 93.0);
       Studentstu3(3, "Chris", 1.1f, 163.4f, 93.5f,90.0f, 83.5f);
       Studentstu2(2, "Bob", 1.5f, 166.6f, 86.0f,98.5f, 85.0f);
       Studentstu1(1, "Andrew", 1.5f, 173.2f, 98.5f,100.0f, 100.f);
 
       stu_map.insert(make_pair(key(stu4.get_eyesight(),stu4.get_height()), stu4));
       stu_map.insert(make_pair(key(stu3.get_eyesight(),stu3.get_height()), stu3));
       stu_map.insert(make_pair(key(stu2.get_eyesight(),stu2.get_height()), stu2));
       stu_map.insert(make_pair(key(stu1.get_eyesight(),stu1.get_height()), stu1));
 
       map<key,Student>::iterator iter;
       for(iter = stu_map.begin(); iter != stu_map.end();++iter)
       {
             cout<< iter->first.eyesight << "\t"<< iter->first.height  << "\t" << iter->second.get_id()<<"\t" <<iter->second.get_name() << endl;
       }
 
       return 0;
}

那么输出结果为:

1.1    163.4        3       Chris

1.1    170.2        4       Dudley

1.5    166.6        2       Bob

1.5    173.2        1       Andrew

从上面的输出,我们可以很明显地看到,是按照视力升序和升高升序输出的,另外三种可能的排序情况,也在类key的操作符“<”的重载函数中,用注释的形式给出了。

 

(3)结论

1.通常我们不用STL algorithm中的sort函数,来对一个map进行排序,而对vector的元素进行排序则可以很方面地使用sort函数;

2.多值组合作为key的情况,需要我们自己定义一个key类,并在该类中重载操作符“<”。


附两个值作为key的情况之完整的实验代码如下:

#include <iostream>
#include <map>
#include <string>
using namespace std; 
 
class key
{
public:
       float eyesight;
       float height;
 
       key(float x, floaty):eyesight(x), height(y)
       {
       }
 
       friend bool operator < (constkey&,const key&);
};
 
bool operator < (constkey& key1,const key& key2)
{
       // 按eyesight升序 + height升序排列
       if(key1.eyesight != key2.eyesight)      
              return (key1.eyesight < key2.eyesight);
       else
              return (key1.height < key2.height);
      
       // 按eyesight降序 + height降序排列
       //if(key1.eyesight != key2.eyesight)    
       //     return(key1.eyesight > key2.eyesight);
       //else                                 
       //     return(key1.height > key2.height);
 
       // 按eyesight升序 + height降序排列
       //if(key1.eyesight != key2.eyesight)    
       //     return(key1.eyesight < key2.eyesight);
       //else                                 
       //     return(key1.height > key2.height);
 
       // 按eyesight降序 + height升序排列
       //if(key1.eyesight != key2.eyesight)    
       //     return(key1.eyesight > key2.eyesight);
       //else                                 
       //     return(key1.height < key2.height);
}
 
class Student
{
private:
         int id;                   //学号
         string name;              // 姓名
         float eyesight;           //视力
         float height;             //身高
         float chinese;            //语文成绩
         float english;            //英文成绩
         float math;               //数学成绩
public:
       Student(int id, string name,floateyesight,float height,float chinese,float english,float math)
       {
              this->id = id;
              this->name = name;
              this->eyesight = eyesight;
              this->height = height;
              this->chinese = chinese;
              this->english = english;
              this->math = math;
       }
 
       int get_id()
       {
              return id;
       }
 
       string get_name()
       {
              return name;
       }
 
       float get_eyesight()
       {
              return eyesight;
       }
 
       float get_height()
       {
              return height;
       }
 
       float get_chinese()
       {
              return chinese;
       }
 
       float get_english()
       {
              return english;
       }
 
       float get_math()
       {
              return math;
       }
};
 
int main(int argc,char**argv)
{
       map<key,Student> stu_map;
 
       Studentstu4(4, "Dudley",1.1f, 170.2f, 90.5f, 89.5f, 93.0);
       Studentstu3(3, "Chris", 1.1f, 163.4f, 93.5f,90.0f, 83.5f);
       Studentstu2(2, "Bob", 1.5f, 166.6f, 86.0f,98.5f, 85.0f);
       Studentstu1(1, "Andrew", 1.5f, 173.2f, 98.5f,100.0f, 100.f);
 
       stu_map.insert(make_pair(key(stu4.get_eyesight(),stu4.get_height()), stu4));
       stu_map.insert(make_pair(key(stu3.get_eyesight(),stu3.get_height()), stu3));
       stu_map.insert(make_pair(key(stu2.get_eyesight(),stu2.get_height()), stu2));
       stu_map.insert(make_pair(key(stu1.get_eyesight(),stu1.get_height()), stu1));
 
       map<key,Student>::iterator iter;
       for(iter = stu_map.begin(); iter != stu_map.end();++iter)
       {
             cout<< iter->first.eyesight << "\t"<< iter->first.height  << "\t" << iter->second.get_id()<<"\t" <<iter->second.get_name() << endl;
       }
 
       return 0;
}