公司网站宣传,不用代码做网站的软件,广告策划公司有哪些,wordpress gii插件文章目录 一、仿函数定义及使用二、仿函数与函数指针的区别三、仿函数与算法的关系四、仿函数的实践用例 在C编程中#xff0c;我们经常需要对数据进行排序、筛选或者其他操作。为了实现这些功能#xff0c;C标准库提供了许多通用的算法和容器#xff0c;而其中一个重要的概… 文章目录 一、仿函数定义及使用二、仿函数与函数指针的区别三、仿函数与算法的关系四、仿函数的实践用例 在C编程中我们经常需要对数据进行排序、筛选或者其他操作。为了实现这些功能C标准库提供了许多通用的算法和容器而其中一个重要的概念就是
仿函数Functor。仿函数是一种行为类似函数的对象它可以被当做函数使用作为算法的参数传递或者在容器中使用。本文将深入探讨仿函数的概念、用法以及在实际开发中的应用希望能够帮助读者更好地理解和应用仿函数这一重要的编程概念。 一、仿函数定义及使用
仿函数Functor 是一种行为类似函数的对象它可以被用作函数并接受参数。在C中仿函数通常是重载了函数调用运算符operator()的类对象。通过重载operator()仿函数可以像函数一样被调用并且可以保存状态信息。
按照操作数划分假定某个类有一个重载的operator()而且重载的operator()要求获取一个参数我们就将这个类称为一元仿函数unary functor如果重载的operator()要求获取两个参数就将这个类称为二元仿函数binary functor。
按照功能划分可分为算数运算Arithmetic、关系运算Rational、**逻辑运算Logical**三大类。
一个简单的例子是比较仿函数它可以用来对数据进行排序。例如可以定义一个比较仿函数来比较两个整数的大小并将其传递给STL中的sort函数来进行排序。
以下是一个简单的比较仿函数的示例
// 定义一个比较仿函数
templateclass T
struct LessThan {bool operator()(T a, T b) const { return a b;}
};
int main() {LessThanint lessThan; // 创建比较仿函数对象std::cout lessThan(3, 5) std::endl; // 使用仿函数对象进行比较std::cout LessThanint()(3, 5) std::endl; // 使用仿函数对象进行比较return 0;
}在这个例子中LessThan是一个仿函数重载了operator()来进行比较。在main函数中我们创建了LessThan的对象lessThan并使用它来比较两个整数的大小。要将某种操作当做算法的参数唯一的办法就是先将该操作可能用于数条以上的指令设计为一个函数再将函数指针当作一个算法的一个参数或是将该操作设计为一个所谓的仿函数从语言层次来看就是一个class再以该仿函数产生一个对象并以此对象作为算法参数的一部分。
//一元仿函数
struct SetKeyOfT{const K operator()(const K key){ return key; }
};
struct MapKeyOfT{const K operator()(const pairK, V kv) { return kv.first; }
};这两个仿函数也称为函数对象分别用于提取不同类型数据的键key。仿函数的主要目的是提供一个可调用对象通常用于算法中作为自定义的比较或操作函数。
仿函数SetKeyOfT是设计用来从单独的键类型为K中提取键本身。它重载了operator()使其能够接受一个类型为K的常量引用作为参数并返回该键的常量引用。
仿函数MapKeyOfT用于从pairK, V中提取键first成员。在C标准库中pair是一个模板类通常用于表示键值对例如在map和unordered_map等容器中。这个仿函数通过重载operator()使其能够接受一个pairK, V类型的常量引用作为参数并返回该pair的键first成员的常量引用。
这在实际应用中可能看起来有些多余但是在我们模仿实现一些数据结构时可以起到作用如仿写set 和 map。 通过使用仿函数我们可以将函数对象作为参数传递给其他函数或者将其存储在容器中从而实现更灵活的编程和功能组合。 二、仿函数与函数指针的区别
函数指针也可以当作参数传递给算法当参数。但是函数指针不能满足 STL对抽象性的要求即无法和STL其他组件搭配。
在STL标准模板库中仿函数也称为函数对象与算法之间存在着密切的关系。STL算法通常接受仿函数作为参数以便能够自定义算法的行为。这种灵活性使得STL算法能够适用于各种不同的场景而不仅仅是预定义的操作。
仿函数functor和函数指针在编程中虽然都有其独特的应用场景但它们在实现方式、使用灵活性和抽象层次等方面存在显著的区别。
首先仿函数是一个类的实例通过重载operator()操作符使得这个类的对象可以像函数一样被调用。这使得仿函数在行为上表现得像一个函数但实际上它拥有类的所有特性如数据成员和成员函数。因此仿函数可以封装更复杂的状态和行为并且可以在类定义中提供更多的灵活性和控制。
相比之下函数指针是一个指向函数的指针变量。它本身是一个指针指向的是函数的入口地址。函数指针主要用于在运行时动态地调用不同的函数或者将函数作为参数传递给其他函数。然而函数指针的使用受到一定的限制因为它只能指向已定义的函数而不能封装更复杂的状态或行为。
在抽象层次上仿函数提供了比函数指针更高层次的抽象。仿函数可以看作是函数指针的泛化它不仅能够像函数指针一样动态地调用不同的函数还能够封装更多的状态和行为。这使得仿函数在使用STL算法等需要高度抽象和灵活性的场合中更为适用。 三、仿函数与算法的关系
首先仿函数在STL中的作用是极大的。
仿函数在STL中的主要作用是提供一种可以像函数一样调用的对象。它们通常通过重载operator()来定义自己的行为从而可以在算法中作为参数传递以决定算法如何操作元素。
算法通常与仿函数进行结合
STL算法是高度通用化的它们通过接受仿函数作为参数来适应不同的操作需求。例如std::sort算法可以对容器进行排序但它并不直接定义如何比较元素。相反它接受一个仿函数作为参数该仿函数定义了如何比较元素。这样你可以为不同的数据类型或排序需求提供不同的比较逻辑。 同样std::transform算法可以对容器中的元素进行转换它接受一个仿函数来定义转换的逻辑。你可以提供一个仿函数来执行任何你想要的转换操作。下面是一个使用仿函数进行排序的示例
#include iostream
#include vector
#include algorithm
using namespace std;
// 定义一个仿函数用于比较两个整数的大小
struct CompareInts {bool operator()(const int a, const int b) const{ return a b; }// 升序比较
};
int main() {vectorint vec {5, 2, 8, 1, 9};// 使用sort算法和自定义的仿函数进行排序sort(vec.begin(), vec.end(), CompareInts());return 0;
}在这个例子中我们定义了一个名为CompareInts的仿函数它重载了operator()来定义如何比较两个整数。然后我们将这个仿函数作为第三个参数传递给sort算法以便按照升序对整数进行排序。
仿函数比起一般函数具有很多优点以下描述错误的是( C ) A.在同一时间里由某个仿函数所代表的单一函数可能有不同的状态 B.仿函数即使定义相同也可能有不同的类型 C.仿函数通常比一般函数速度快 D.仿函数使程序代码变简单 A.仿函数是模板函数可以根据不同的类型代表不同的状态 B.仿函数是模板函数可以有不同类型 C.仿函数是模板函数其速度比一般函数要慢,故错误 D.仿函数在一定程度上使代码更通用本质上简化了代码 ⚠️我们如果要使用STL内建的仿函数都必须含 functional头文件。 四、仿函数的实践用例
我们拿leetoce中的题目来做案例692. 前K个高频单词 - 力扣LeetCode。题目如下
给定一个单词列表 words 和一个整数 k 返回前 k 个出现次数最多的单词。
返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率 按字典顺序 排序。
示例 1
输入: words [i, love, leetcode, i, love, coding], k 2
输出: [i, love]
解析: i 和 love 为出现次数最多的两个单词均为2次。注意按字母顺序 i 在 love 之前。示例 2
输入: [the, day, is, sunny, the, the, the, sunny, is, is], k 4
输出: [the, is, sunny, day]
解析: the, is, sunny 和 day 是出现次数最多的四个单词出现次数依次为 4, 3, 2 和 1 次。注意
1 words.length 5001 words[i] 10words[i] 由小写英文字母组成。k 的取值范围是 [1, 不同 words[i] 的数量]
class Solution {
public:class Com{public:bool operator()(const pairstring,int kv1, const pairstring,int kv2){return kv1.second kv2.second || (kv1.second kv2.second kv1.first kv2.first) ;}};vectorstring topKFrequent(vectorstring words, int k) {mapstring,int mp;for(auto e : words)mp[e];vectorpairstring,int ans(mp.begin(),mp.end()); sort(ans.begin(),ans.end(),Com());auto it ans.begin();vectorstring ret;while(k--){ret.push_back(it-first);it;}return ret;}
};Com是一个嵌套的仿函数它重载了operator()以提供自定义的比较逻辑。这个仿函数用于对pairstring, int类型的元素进行比较其中string代表单词int代表该单词的出现频率。
整体解题思路如下
统计频率topKFrequent函数首先遍历输入的字符串数组words并使用map数据结构mp统计每个单词的出现频率。创建向量接着它将map中的元素键值对复制到一个vectorpairstring, int类型的向量ans中。排序然后它使用sort函数对ans进行排序。排序时使用了之前定义的仿函数Com作为比较函数因此排序结果会按照单词频率的降序和字典序的升序进行排列。提取结果最后程序使用一个迭代器it遍历排序后的ans并将前k个单词即频率最高的k个单词添加到结果向量ret中。返回结果函数返回包含前k个最频繁单词的ret向量。
本题通过使用仿函数实现了自定义的比较逻辑这种比较逻辑确保了在排序后出现频率高的单词会排在前面如果频率相同则字典序小的单词排在前面。使得我们可以按照特定的顺序对单词进行排序并最终提取出出现频率最高的前k个单词。