IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> Term45:正确区分count、find、binary_search、lower_bound、upper_bound和equal_range。 -> 正文阅读

[C++知识库]Term45:正确区分count、find、binary_search、lower_bound、upper_bound和equal_range。

????????前情提示:我个人认为本条款Term45是《Effective STL》这本书中最重要的其中一个term!它不仅告诉我们如标题所述的几种算法的具体使用的规范,还提醒我们,应该如何在使用STL容器时do规范的查找操作!

????????假设我有一个容器,或者有一对迭代器标识了一个区间,now你希望在容器or区间中查找一些信息,这样的查找工作该如何进行呢?你的选择往往是:count、count_if、find、find_if、binary_search、lower_bound、upper_bound及equal_range。你究竟该如何选择呢?

????????case1:区间被排过序时,建议你优先选择binary_search、lower_bound、upper_bound及equal_range,因为这样会获得更快的查找速度。

????????case2:区间没有被排过序时,建议你优先选择count、count_if、find、find_if。(若不这么选择,那么你得先sort(),然后再像case1那样去使用binary_search、lower_bound、upper_bound及equal_range这几个算法也是可以的,只不过效率较低而已!)

下面我直接用测试代码对这几种查找算法予以讨论!

test_codes:(请仔细耐心地reading)

#include<iostream>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<functional>
#include<list>
using namespace std;
struct myPred :public binary_function<Widget, Widget,bool> {
	bool operator()(const Widget& w1, const Widget& w2)const {
		return w1.getWeight() < w2.getWeight();
	}
};
struct Widget {
private:
	double m_weight;
public:
	Widget(double mw=0.0):m_weight(mw){}
	double getWeight() const{ return m_weight; }
	bool operator==(const Widget& w)const {
		return  w.getWeight() == this->getWeight();
	}
};
int main(void) {
	list<Widget> lw{ Widget(2.38),Widget(8.38) };
	Widget w(2.381);
	if (count(lw.begin(), lw.end(),w)!=0) {//用count做存在性的测试!!!
		cout << "w在lw中!" << endl;
	}
	else {
		cout << "w不在lw中!" << endl;
	}

	if (find(lw.begin(), lw.end(), w) != lw.end()) {
		cout << "w在lw中!" << endl;//并且,这里find返回的是第一个满足条件的对象的iterator!
	}
	else {
		cout << "w不在lw中!" << endl;
	}
	vector<Widget> vw{ Widget(2.38),Widget(8.38) };
	Widget w2(2.38);
	sort(vw.begin(), vw.end(),myPred());
	//注意!这里使用sort算法和binary_search算法的函数调用中都必须是同一个Pred!否则编译通过不了!
	if (binary_search(vw.begin(), vw.end(), w2, myPred())) {
		cout << "w2在vw中!" << endl;
	}
	else {
		cout << "w2不在vw中!" << endl;
	}

	//binary_search() 算法函数:回答的是-该容器区间中 是否 存在 这样一个给定的value的elem
	//lower_bound() 算法函数:回答的是-该值在容器区间中吗?如果在,它的第一份拷贝在哪里?
	//如果不在,它该往哪里插入呢?

	//注意:与find算法函数一样的是,你必须测试lower_bound的结果,以便判断它是否指向你要找的值
	//与find不一样的是,你不能用end()迭代器来测试lower_bound的返回值。
	//相反,你必须测试你的lower_bound的返回值所标识的对象,以便判断该对象是否具有你想要找的值!
	
	//许多程序员会按照如下方式来使用lower_bound:
	auto it = lower_bound(vw.begin(), vw.end(), w2, myPred());
	if (it != vw.end() && *it == w2) {//×!!!
		//确保it指向一个对象,并且确保该对象有正确的值
		//if找到该值,则it指向第一个具有该值的对象!
	}
	else {
		//没有找到
	}
	//虽然在大部分case下这段代码可以正常工作,但这段代码是错误的!
	//正确的做法是你必须检查lower_bound返回的迭代器所指向的对象是否等价于你要查找的值!
	//(当然,所用的Pred也必须保持一致!)
	auto it = lower_bound(vw.begin(), vw.end(), w2, myPred());
	if (*it == w2) {//√!!!
		//确保it指向一个对象,并且确保该对象有正确的值
		//if找到该值,则it指向第一个具有该值的对象!
	}
	else {
		//没有找到
	}

	//有一种比上述算法函数更加简单的算法函数,可以用于排序了的区间查找某个给定值
	//equal_range():返回一个迭代器对组(pair<iterator1,iterator2> )
	//iterator1 返回 == lower_bound返回的迭代器(即指向该区间中与所查找的值等价的第一个元素的位置)
	//iterator2 返回 == upper_bound返回的迭代器(即指向该区间中与所查找的值等价的最后一个元素的下一个位置)
	//if找不到,则iterator1和iterator2都指向w的(合适的)插入位置
	
	//so equal_range()返回的这一对迭代器标识了一个子区间,其中的值与你所查找的值等价。
	//关于该算法函数的返回值 有2个需要注意的地方:
	//注意1-如果返回的2个迭代器相同,则表明查找所得到的对象区间为空,即没有找到这样的值
	//这对于使用equal_range来回答“是否存在这样的值”是非常关键的!
	vector<Widget> vw2{ Widget(2.38),Widget(8.38) };
	Widget w3(2.38);
	sort(vw2.begin(), vw2.end(), myPred());
	//注意!这里使用sort算法和binary_search算法的函数调用中都必须是同一个Pred!否则编译通过不了!
	auto IterPair = equal_range(vw2.begin(), vw2.end(), w3, myPred());
	if (IterPair.first == IterPair.second) {
		cout << "w2不在vw中!" << endl;//如果equal_range沒有找到所要查找的特定值
		//pair.first 和 pair.second 都指向w的插入位置
	}
	else {
		cout << "w2不在vw中!" << endl;//非空区间,则表明找到了特定值,
		//此时pair.first指向第一个与特定值等价的对象,pair.second指向最后一个与特定值等价的下一个位置
	}

	//注意2- equal_range()所返回的迭代器 之间的距离 与这个区间中的 对象数目 是相等的。
	//so,可以这么说,对于排了序的容器区间来讲,equal_range不仅仅完成了find的工作,还完成了count的工作!

	vector<Widget> vw3{ Widget(2.38),Widget(8.38),Widget(2.38),Widget(2.38) };
	Widget w4(2.38);
	sort(vw3.begin(), vw3.end(), myPred());
	auto VWIterPair = equal_range(vw3.begin(), vw3.end(), w4, myPred());
	cout << "There are " << distance(VWIterPair.first, VWIterPair.second) <<
		" elements in vw3 equivalent to w4." << endl;
	return 0;
}

总结

????????①binary_search() 算法函数:回答的是-该容器区间中 是否 存在 这样一个给定的value的elem,该函数返回值是true(存在) or false(不存在)。

????????②lower_bound() 算法函数:回答的是-该值在容器区间中吗?如果在,它的第一份拷贝在哪里?
如果不在,它该往哪里插入呢?该函数的返回值是指向该值等于给定值的第一份拷贝的迭代器(存在)or指向一个合适的插入给定值target对象到该容器中的位置的迭代器(注意,这里不一定是container.end()!不要乱来!)。

? ? ? ? ---注意:与find算法函数一样的是,你必须测试lower_bound的结果,以便判断它是否指向你要找的值。与find不一样的是,你不能用end()迭代器来测试lower_bound的返回值。相反,你必须测试你的lower_bound的返回值所标识的对象,以便判断该对象是否具有你想要找的值!

????????③upper_bound() 算法函数:回答的是-该值在容器区间中吗?如果在,它的最后一份拷贝的下一个位置在哪里?如果不在,它该往哪里插入呢?该函数的返回值是指向该值等于给定值的最后一份拷贝的下一个位置的迭代器(存在)or指向一个合适的插入给定值target对象到该容器中的位置的迭代器(注意,这里不一定是container.end()!不要乱来!)。

????????④equal_range()算法函数(比用上述算法来查找给定value的elem更好,推荐查找时使用!):可以用于在排序了的区间中查找某个给定值。该函数返回一个迭代器对组(pair<iterator1,iterator2> )
? ? ? ? ---iterator1 返回 == lower_bound返回的迭代器(即指向该区间中与所查找的值等价的第一个元素的位置)
????????---iterator2 返回 == upper_bound返回的迭代器(即指向该区间中与所查找的值等价的最后一个元素的下一个位置)
????????---if找不到,则iterator1和iterator2都指向w的(合适的)插入位置,且这个合适的位置是由该算法函数本书来找的,不是我们自定义的。

????????⑤对于标准序列式(Sequence Containers)容器(vector,string,deque,list)而言,使用通用的STL算法count、count_if、find、find_if、binary_search、lower_bound、upper_bound及equal_range来do查找操作

? ? ? ? ⑥对于标准关联式(Associative Containers)容器(map/multimap,set/multiset,unordered_map,unordered_set)而言,则使用该容器本身的成员函数.count()、.find()、.lower_bound()、.upper_bound()及.equal_range()来do查找操作

? ? ? ? 注意:这些与通用STL查找算法同名的成员函数往往比前者要好!(Effective STL Term44说明了,容器的成员函数往往比通用同名的STL算法好!)简而言之,即这些成语函数代码的执行速度更快!使用方便,行为方式也更自然!

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-04 10:51:31  更:2022-02-04 10:53:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:07:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码