微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C++ sort函数中cmp()比较函数的写法

(部分内容搬运,来源见文章底部

sort函数中的cmp比较函数

sort函数中的比较函数cmp(),即void sort( iterator start, iterator end, StrictWeakOrdering cmp );
sort函数文件为:#include <algorithm>
其中,cmp函数可以自己编写,自己决定逻辑,包括cmp的命名也是自己决定的。

示例如下:

bool cmp(int a ,int b)
{
	return a < b ;		从小到大排序,把 < 换成 > 就是从大到小 
}

sort(p.begin(), p.end(), cmp);

其中的比较逻辑可以任意定义,也可以传入数组或对象,依据多重数据来嵌套排序(例如,球队按积分从高到低排序,积分相同的按净胜球排序,净胜球相同的按进球排序,进球相同的按球队名字典序排序——某厂笔试题)。

例如:传入两个数组(只有0、1元素),按[0]从大到小排序,如果[0]相同,按[1]从小到大排序。

 static bool cmp(const vector<int>& a, const vector<int>& b) {
        if (a[0] == b[0]) return a[1] < b[1];	[0]相同则比较[1]
        return a[0] > b[0];  					比较[0]
    }

注意到,其中和cmp函数的示例有以下不同:

1. 形参写成了const引用的形式
2. 函数更改为静态函数static

关于1:当引用作为形参,函数调用时也可以看成将传递的实参绑定给它,这样我们在函数体内对这个引用做的一切操作都有可能影响到函数传递的实参。如果我们希望参数在函数体内是只读的,所以当我们加了引用有希望参数是只读的就必须加 const。
为什么不直接值传递呢? 确实,但是当参数是类对象时值传递就有了一个问题,那就是性能可能会大受影响。我们知道值传递实际就是向函数拷贝一份副本来使用,那么对于一些复杂的类,尤其是 string 这样每一次拷贝可能消耗很多的时间,那么通过引用传参就很有必要了。
总的来说因为我想提高类对象传参时的性能,所以要用引用,因为用了引用我又希望它只读所以我用了const。

关于2:在(非静态成员)函数的返回类型前加上关键字static,函数就被定义成为静态函数。普通 函数的定义和声明认情况下是extern的,但静态函数只是在声明他的文件当中可见,不能被其他文件所用。因此定义静态函数有以下好处:
  <1> 其他文件中可以定义相同名字的函数,不会发生冲突。
  <2> 静态函数不能被其他文件所用。

另一种直接定义在sort中(courses是二维数组,按c[1]从小到大排)

sort(courses.begin(), courses.end(), [](const auto& c0, const auto& c1) {return c0[1] < c1[1];});

也可以传入一个x,返回和x操作后的排序

sort(arr.begin(), arr.end(), [x](int a, int b) -> bool {
            return abs(a - x) < abs(b - x) || abs(a - x) == abs(b - x) && a < b;
        });

下面是一个case:对结构体People的对象排序,按年龄从小到大,年龄相同的按姓名字典序。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

class People {
public:
	int age;
	string name;
	
	People(int a, string n) :age(a), name(n) {}
};

bool cmp(People a, People b)//一定要写在class People后面,否则报错
{
	if (a.age == b.age)return a.name < b.name;//年龄相同时,姓名字典序
	return a.age < b.age;		//年龄从低到高
}

int main() {
	vector<People>p;
	People p1(17, "Bob");
	People p2(32, "Z");
	People p3(6, "Alice");
	People p4(32, "MM");
	People p5(32, "FFF");
	People p6(15, "MM");
	p.push_back(p1);
	p.push_back(p2);
	p.push_back(p3);
	p.push_back(p4);
	p.push_back(p5);
	p.push_back(p6);

	for (int i = 0; i < p.size(); i++)
		cout << "age" << p[i].age << " name" << p[i].name << endl;
		//age17 nameBob
		//age32 nameZ
		//age6 nameAlice
		//age32 namemm
		//age32 nameFFF
		//age15 namemm
	sort(p.begin(), p.end(), cmp);

	for (int i = 0; i < p.size(); i++)
		cout << "age" << p[i].age << " name" << p[i].name << endl;
	cout << endl;
		//age6 nameAlice
		//age15 namemm
		//age17 nameBob
		//age32 nameFFF
		//age32 namemm
		//age32 nameZ
	return 0;
}

STL容器中的cmp比较函数

在C++中,我们经常需要用到set,map等容器,他们的cmp基本写法都与sort的相同,当然set,map的cmp可不仅仅是函数了,而是函数对象。

struct cmp{
	bool operator ()(const int a , const int b)
	{
		return a < b ;			// 从小到大,反过来就是从大到小 
	}
};

下面是对set做的代码测试:

#include <iostream>
#include <cstring>
#include <set>
 
using namespace std ;
 
struct Person{
	int age;
	char name[20];
	Person(int Age , const char Name[]):age(Age){strcpy(name,Name);}
};
struct cmp{
	bool operator ()(const Person a , const Person b)
	{
		return a.age < b.age ;			//	从小到大 ; 
	}
};
 
int main()
{
	set<Person,cmp> s ;
	Person n1(46,"ggg");
	Person n2(-16,"fff");			//年龄无负数,只是为了测试代码,下同 
	Person n3(45,"eee");
	Person n4(-25,"ddd");
	Person n5(34,"ccc");
	Person n6(22,"bbb");
	Person n7(2,"aaa");
	s.insert(n1);
	s.insert(n2);
	s.insert(n3);
	s.insert(n4);
	s.insert(n5);
	s.insert(n6);
	s.insert(n7);
	set<Person,cmp>::iterator begin = s.begin();
	set<Person,cmp>::iterator end = s.end();
	for(set<Person,cmp>::iterator i = begin ; i != end ; ++i)
	{
		cout<<i->age<<" "<<i->name<<endl ;
	}
	return 0 ;
}

文章来源:
《浅谈C/C++排序函数中cmp()比较函数的写法》
《C++ 关于函数形参中const的作用》
《static修饰的函数作用与意义》

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐