关于C++中定义比较函数的三种方法小结

C++编程优与Pascal的原因之一是C++中存在STL(标准模板库)。STL存在很多有用的方法。

C++模板库中的许多方法都需要相关参数有序,例如Sort()。显然,如果你想对一个集合进行排序,你必须要知道集合中的对象,那个在前那个在后。因此,学会如何定义比较方法是非常重要的。

C++模板库的许多容器需要相关类型有序,例如set<T> 和priority_queue<T>。

这篇文章旨在告诉大家如何为一个类定义一个排序方法,以便在STL容器或者方法中使用。 作为一个C++程序员,你应该知道这些方法。

如何定义排序?

简而言之,为一个类定义排序,我们就可以知道类的任意两个对象在排序的过程中谁在前谁在后。我们可以用一个方法来实现,这个方法返回一个bool值表示谁排在前面。显然,我们希望实现一个类似,f(x,y),这种形式的方法。它接收同一类型的对象作为两个参数,返回值则表明谁会出现在谁前面。

严格弱序化

几乎所有的方法或容器都需要排序来满足数学意义上的标准严格弱序化,否则这些方法或容器的行为将不可预知。

假设f(x,y)是一个比较函数。 如果该函数满足如下条件则它是严格弱序化的。

1.f(x,x) = false;

2. if f(x,y) then !f(y,x)

3.if f(x,y) and f(y,z) then f(x,z)

4. if !f(x,y)&&!f(y,x) then x==y; if x==y and y==z then x==z;

看上去有点晕乎,不过不用担心,只要你的比较方法能够满足对相等元素永远返回false,那你的方法就满足要求了。

三种实现方式:

1. 定义 < 操作符。

使用这种方法可以使我们自定义的类能够获得与生俱来的排序能力。例如,如果有如下类:

struct Edge
{
int from,to ,weight;
};

因为要实现Kruskai算法,你希望图中的所有边依据权重按降序排列。 像这样来定义 operator<:

struct Edge
{
    int from,to ,weight;
    bool operator <(Edge other) const
    {
        return weight>other.weight;
    }
};  

你定义的方法必须按照如下方法声明:

bool operator< (T other) const

注意: const关键字是必须的。

如果你不喜欢这种方式,比如,明明是要比较两个对象,方法却只有一个参数。你可以选择如下方式:

struct Edge
{
  int from,to weight;
  friend bool operator<(Edge a,Edge b)
  {
    return a.weight>b.weight;
  }
};

STL的pair<T1,T2>就具有与生俱来的排序能力。两个pair对象的比较这样的:先比较第一个参数,如果第一个参数相同再比较第二个参数。

所有内置类型都具有与生俱来的排序能力,这是由编译器赋予的。

2. 自定义排序方法。

使用这种方式常常用在如下情形:

a.比较内置类型

b.不能修改需要比较的类型

c.除了类型自定义的比较方式以外的比较方法

简单来说,一个比较方法接收两个同类型的对象作为参数并且返回一个bool值,原型如下:

bool name(T a,T b);
 
3. 重载()操作符

我们可以将比较函数作为STL容器构造函数的第一个参数,并且把函数类型作为模板参数。例如:

set<int,bool (*)(int,int)> s(cmp);

这样做或多或少会让人费解。那我们就来看看如何使用仿函数来消除你的疑惑吧。

我们需要定义一个新的类并重载()操作符。

vector<int> occurrences;
struct cmp
{
  bool operator()(int a, int b)
  {
    return occurrences[a] < occurrences[b];
  }
};

现在我们就可以把这个类作为模板参数传递给STL容器了。

set<int, cmp> s;

priority_queue<int, vector<int>, cmp> pq;

STL也有一些内置的仿函数,例如less<T>,greater<T>等。

仿函数可以通过初始化然后像普通函数一样使用。最简单的就是在仿函数后面加上()。

sort(data.begin(), data.end(), greater<int>());

以上就是小编为大家带来的关于C++中定义比较函数的三种方法小结全部内容了,希望大家多多支持我们~

(0)

相关推荐

  • C++中函数的用法小结

    函数在C++中的使用,无非2种地方,一处是函数的定义,一处是函数的调用.而函数的定义则非常简单,由三个部分组成:函数的返回类型.函数名和函数的形参表.当然,这里不同的函数定义可以还会稍有不同,比如类的成员函数.内联函数等.这里我们主要讨论函数的调用时需要注意的一些问题. 一.参数传递 我们将函数定义或声明里的参数叫形参,而在调用函数时传入的参数叫实参.那么根据形参类型的不同,有几下形式的参数传递. 1,非引用形参 1)普通的内置类型 普通非引用类型的参数通过复制对应的实参实现形参的初始化.当用实

  • C/C++函数调用的几种方式总结

    调用函数时,计算机常用栈来存储传递给函数的参数. 栈是一种先进后出的数据结构,栈有一个存储区.一个栈顶指针.栈顶指针指向堆栈中第一个可用的数据项(被称为栈顶).用户可以在栈顶上方向栈中加入数据,这个操作被称为压栈(Push),压栈以后,栈顶自动变成新加入数据项的位置,栈顶指针也随之修改.用户也可以从堆栈中取走栈顶,称为弹出栈(pop),弹出栈后,栈顶下的一个元素变成栈顶,栈顶指针随之修改.函数调用时,调用者依次把参数压栈,然后调用函数,函数被调用以后,在堆栈中取得数据,并进行计算.函数计算结束以

  • 关于C++中定义比较函数的三种方法小结

    C++编程优与Pascal的原因之一是C++中存在STL(标准模板库).STL存在很多有用的方法. C++模板库中的许多方法都需要相关参数有序,例如Sort().显然,如果你想对一个集合进行排序,你必须要知道集合中的对象,那个在前那个在后.因此,学会如何定义比较方法是非常重要的. C++模板库的许多容器需要相关类型有序,例如set<T> 和priority_queue<T>. 这篇文章旨在告诉大家如何为一个类定义一个排序方法,以便在STL容器或者方法中使用. 作为一个C++程序员,

  • JavaScript中定义函数的三种方法

    在JavaScript的世界里,定义函数的方法多种多样,这正是JavaScript灵活性的体现,但是正是这个原因让初学者摸不着头脑,尤其对于没有 语言基础的同学.正所谓条条大道通罗马,但是如果道路太多,会让行路者不知所措,因为不知道走那条路才是正途,呵呵,废话一大篇,闲言少叙,先看代码: 复制代码 代码如下: /*第一种方法,使用function语句,格式如下*/ function fn(){ alert("这是使用function语句进行函数定义"); } fn(); /*第二种方法

  • vue中锚点的三种方法

    第一种: router.js中添加 mode: 'history', srcollBehavior(to,from,savedPosition){ if(to.hash){ return { selector:to.hash } } } 组件: <template> <div> <ul class="list"> <li><a href="#1" rel="external nofollow"

  • JavaScript定义数组的三种方法(new Array(),new Array('x','y')

    如下所示: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Co

  • Android中使用定时器的三种方法

    本文实例为大家分享了Android中使用定时器的三种方法,供大家参考,具体内容如下 图示: 因为都比较简单,所以就直接贴代码(虑去再次点击停止的操作),有个全局的Handler负责接收消息更新UI 第一种方法:Thread.sleep();方法 Runnable runnable = new Runnable() { @Override public void run() { while (true) { mHandler.sendEmptyMessage(0); try { Thread.sl

  • jQuery中each遍历的三种方法实例分析

    本文实例讲述了jQuery中each遍历的三种方法.分享给大家供大家参考,具体如下: 1.选择器+遍历 $('div').each(function (i){ //i就是索引值 //this 表示获取遍历每一个dom对象 }); 2.选择器+遍历 $('div').each(function (index,domEle){ //index就是索引值 //domEle 表示获取遍历每一个dom对象 }); 3.更适用的遍历方法 1)先获取某个集合对象 2)遍历集合对象的每一个元素 var d=$(

  • python中实现栈的三种方法

    栈是一种线性数据结构,用先进后出或者是后进先出的方式存储数据,栈中数据的插入删除操作都是在栈顶端进行,常见栈的函数操作包括 empty() – 返回栈是否为空 – Time Complexity : O(1) size() – 返回栈的长度 – Time Complexity : O(1) top() – 查看栈顶元素 – Time Complexity : O(1) push(g) – 向栈顶添加元素 – Time Complexity : O(1) pop() – 删除栈顶元素 – Time

  • 详解JavaScript中分解数字的三种方法

    本文基于免费代码营基本算法脚本"分解数字" 在数学中,非负整数n的阶乘可能是一个棘手的算法.在本文中,我将解释这种方法,首先使用递归函数,第二种使用而循环,第三种使用以循环. 算法挑战 返回提供的整体的阶乘. 如果整体用字母n表示,则阶乘是所有小于或等于n的正整数的乘积. 阶乘经常用简写符号n!表示! 例如:5!= 1 * 2 * 3 * 4 * 5 = 120 function factorialize(num) { return num; } factorialize(5); 提供

  • python求绝对值的三种方法小结

    如下所示: 1.条件判断 2.内置函数abs() 3.内置模块 math.fabs abs() 与fabs()的区别 abs()是一个内置函数,而fabs()在math模块中定义的. fabs()函数只适用于float和integer类型,而abs()也适用于复数. abs()返回是float和int类型,math.fabs()返回是float类型 以上这篇python求绝对值的三种方法小结就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • Python 循环终止语句的三种方法小结

    在Python循环终止语句有三种: 1.break break用于退出本层循环 示例如下: while True: print "123" break print "456" 2.continue continue为退出本次循环,继续下次循环 示例如下: while True: print "123" continue print "456" 3.自定义标记 Tag 自已定义一个标记为True或False 示例代码: Tag

随机推荐