C++自定义sort比较函数的四种方法

发布时间 2024-01-12 13:20:47作者: 真昼小天使daisuki

sort函数:对于容器等进行排序,头文件位于<algorithm>中。

普通:可以在sort的第三个参数传入

  • 无参:default = less<>()
  • less<>():默认升序
  • greater<>():默认降序

另外,可以通过自定义的方式来设置sort()的比较函数

引用:https://bbs.huaweicloud.com/blogs/detail/312149

方式1:传入自定义函数指针,(有人也称为回调函数)

    bool cmp2(int a, int b) //从大到小
    {
        return a > b;
    }
    sort(num, num + 4, cmp2);

方式2:传入一个包含仿函数的对象

引用: https://zhuanlan.zhihu.com/p/362323211

仿函数:定义一个类,类里面定义了某个方法,将该类的对象作为函数的入参,那么在函数中就能调用这个类中的方法。
或者,定义一个类,类里面重载函数运算符(),将该类的对象作为函数的入参,那么在函数中同样能调用重载符()里面的方法

函数对象的出现是为了代替函数指针的,最明显的一个特点是:可以使用内联函数。而如果使用内联函数的指针,编译器会把它当普通函数对待。另外,函数对象是类封装的,代码不但看起来简洁,设计也灵活,比如还可以用关联,聚合,依赖的类之间的关系,与用到他们的类组合在一起,这样有利于资源的管理(这点可能是它相对于函数最显著的优点了)。

仿函数(Functor)也是 STL 六大模块之一,其余 5 个分别是容器(Container)、算法(Algorithm)、迭代器(Iterator)、适配器(Adapter)和分配器(Allocator)。

    class cmp
    {
        public:
        bool operator()(int a, int b) //从小到大
        {
            return a < b;
        }
    };
    sort(num, num + 4, cmp());

方式3:重载 < 运算符

通常用于自定义数据类型,如结构体和类等。

bool operator< (const Student& s1, const Student& s2)
{
    if(s1.age==s2.age)
        return s1.name <s2.name;//年龄相同时,按姓名小到大排
    else  
        return s1.age > s2.age; //从年龄大到小排序
}
sort(a,a+n);

方式4:lambda匿名函数

另外,对于规模较小的比较函数,lambda有时是一个更简洁的选择。

	//lambda表达式定义排序规则
	sort(ret.begin(), ret.end(),[](pair<int, int >a, pair<int, int >b) 
	 { if (a.second != b.second) return a.second < b.second; else return a.first < b.first;});

源代码阅读:sort

    template<class _RanIt,
    class _Pr> inline
    void sort(_RanIt _First, _RanIt _Last, _Pr _Pred)
    {	// order [_First, _Last), using _Pred
        _DEBUG_RANGE(_First, _Last);
        _DEBUG_POINTER(_Pred);
        _Sort(_Unchecked(_First), _Unchecked(_Last), _Last - _First, _Pred);
    }
    // TEMPLATE FUNCTION sort
    template<class _RanIt> inline
    void sort(_RanIt _First, _RanIt _Last)
    {	// order [_First, _Last), using operator<
        _STD sort(_First, _Last, less<>());
    }

源代码阅读:_Sort

template<class _RanIt,
	class _Diff,
	class _Pr> inline
	void _Sort(_RanIt _First, _RanIt _Last, _Diff _Ideal, _Pr _Pred)
{	// order [_First, _Last), using _Pred
	_Diff _Count;
	for (; _ISORT_MAX < (_Count = _Last - _First) && 0 < _Ideal; )
	{	// divide and conquer by quicksort
		pair<_RanIt, _RanIt> _Mid =
			_Unguarded_partition(_First, _Last, _Pred);
		_Ideal /= 2, _Ideal += _Ideal / 2;	// allow 1.5 log2(N) divisions
		if (_Mid.first - _First < _Last - _Mid.second)
		{	// loop on second half
			_Sort(_First, _Mid.first, _Ideal, _Pred);
			_First = _Mid.second;
		}
		else
		{	// loop on first half
			_Sort(_Mid.second, _Last, _Ideal, _Pred);
			_Last = _Mid.first;
		}
	}
	if (_ISORT_MAX < _Count)
	{	// heap sort if too many divisions
		_STD make_heap(_First, _Last, _Pred);
		_STD sort_heap(_First, _Last, _Pred);
	}
	else if (1 < _Count)
		_Insertion_sort(_First, _Last, _Pred);	// small
}

注:以上代码来源于引用链接,但是我看了下MSVC C++ 20下的algorithm代码,除了宏命名以外,基本逻辑没有太大区别。

STL库函数的实现是:快速排序 + 堆排序 + 插入排序
首先调用快排,对于数据进行依据pivot的分割,递归调用,
对于较大的数据(_ISORT_MAX < _Count),建立heap堆排序,
对于较小的数据:插入排序