【STL】查找

#include<algorithm>

binary_search

该函数功能是查找指定元素是否存在,存在返回true, 不存在返回false
函数原型:bool binary_search(iterator beg, iterator end, value);

注意:该函数内部通过二分查找实现,二分查找法查找效率很高,但是查找的容器中元素必须的有序序列,所以一定要从小到大排序后进行查找。

实例:

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

int main() {
	vector<int> vec;
	for (int i = 0; i < 10; ++i) vec.push_back(i);
	bool judge = binary_search(vec.begin(), vec.end(), 5);
	if (judge == true) {
		cout << "找到了该元素!!" << endl;
	}
	else {
		cout << "没有找到该元素!!" << endl;
	}
	return 0;
}

lower_bound() 和 upper_bound()

这两个算法用于在已排序序列中执行范围查找。(底层皆基于二分查找)
std::lower_bound 返回第一个大于等于给定值的元素的迭代器,
std::upper_bound 返回第一个大于给定值的元素的迭代器。
如果没找到,返回末尾的迭代器位置。

实例:

#include<iostream>
#include<vector>
#include<algorithm>
int main() {
	std::vector<int> vec = {2, 4, 4, 4, 7, 9};
    auto low = std::lower_bound(vec.begin(), vec.end(), 4);
    auto up = std::upper_bound(vec.begin(), vec.end(), 4);
    std::cout << "第一个 4 的位置:" << std::distance(vec.begin(), low) + 1 << '\n';
    std::cout << "第一个大于 4 的位置:" << std::distance(vec.begin(), up) + 1 << '\n';
	return 0;
}

下面以LeetCode简单算法题为例:

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。
如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

常规解法:

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int length = nums.size();
        int left=0,right=length 1;
        while(left<=right){
            int mid=left+(right-left)/2; // 这里一定要注意不仅仅是尾部减去首部除以二 还需加上尾部下标
            if(nums[mid]<target)
                left=mid+1;
            else right=mid-1;
        }
        return left;
    }
};

STL解法:

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        return lower_bound(nums.begin(),nums.end(),target) - nums.begin();
    }
};

map/set
这里用法有点不同,拿set举例:
相对于数组以算法的形式使用,set 输入时已经建好树(不需要algorithm头文件), 而algorithm要多一个类似建树的过程。所以 set 有 s.lower_bound(x) 算法,使用该函数肯定 set 快一点

  • set::lower_bound(x):返回set中第一个大于或等于 x 的迭代器指针
  • set::upper_bound(x):返回set中第一个大于 x 的迭代器指针

实例:

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

int main() {
	map<int, int> hash;
	vector<int> vec{1,2,1,3,4,5,6,4,3,2,5,4,3,2,11};
	for (int i : vec) hash[i]++;
	map<int, int>::iterator it = hash.lower_bound(10);
	cout << "大于等于10的数为:" << it -> first << endl;
	cout << "该数有" << it -> second << "个" << endl;
	return 0; 
}

equal_range

std::equal_range 结合了 lower_bound()upper_bound() 的功能,返回一个范围,表示所有与给定值相等的元素。

equal_range 根据键值,返回一对迭代器的pair对象。如果该键值在容器中存在,则pair对象中的第一个迭代器指向该键关联的第一个实例,第二个迭代器指向该键关联的最后一个实例的下一位置。如果找不到匹配的元素,则pair对象中的两个迭代器都将指向此键应该插入的位置。总之,equal_range返回迭代器位置区间 [ lower_bound, upper_bound )

实例1:

#include <iostream>
#include <algorithm>
#include <vector>
int main ()
{
  std::vector<int> vec = {2, 4, 4, 4, 7, 9};
  auto range = std::equal_range(vec.begin(), vec.end(), 4);
  std::cout<<"范围是从位置 "<<std::distance(vec.begin(),range.first)+1<<"到"
  <<std::distance(vec.begin(),range.second)<<'\n';
  return 0;
}

参考代码.first和.second都加了1,但输出结果不对;而只给.first+1,结果就对了。

我想是因为equal_range返回迭代器位置区间 [ lower_bound, upper_bound ) 左闭右开

实例2:

#include <iostream>
#include <map>
int main ()
{
  std::multimap<char,int> my_multimap;
  my_multimap.insert(std::make_pair('a',10));
  my_multimap.insert(std::make_pair('a',20));
  my_multimap.insert(std::make_pair('a',30));
  my_multimap.insert(std::make_pair('a',40));
  my_multimap.insert(std::make_pair('b',10));
  my_multimap.insert(std::make_pair('c',10));
  my_multimap.insert(std::make_pair('c',20));
  std::cout << my_multimap.size() << std::endl;
  std::pair<std::multimap<char,int>::iterator,std::multimap<char,int>::iterator> ret;
  ret=my_multimap.equal_range('a');
  for(std::multimap<char,int>::iterator it=ret.first;it !=ret.second;it++){
        std::cout << it->first << " => " << it->second << '\n';
  }
  return 0;
}

输出:

7
a => 10
a => 20
a => 30
a => 40

从上面例子可以看出,使用了multimap是可以存储重复的键值的,所以使用equal_range开始找’a’键,发现满足条件的有4个,这时返回2个迭代器,第一个迭代器是’a’:10这一组键值对,第二个迭代器是最后一个’a’:40这组满足条件的键值对的后一个键值对’b’:10。因此迭代打印时就会得到一堆输出。

如果没有找到满足条件的键值,那么就会返回最应该插入的位置,这时第一个迭代器和第二个迭代器是相等的。
如果是用map,那么键唯一,也就是将上述代码中的multimap被替换为map,这时下面代码所得到的结果就是’a’键对应的值10。

#include <iostream>
#include <map>
int main ()
{
  std::map<char,int> my_map;
  my_map.insert(std::make_pair('a',10));
  my_map.insert(std::make_pair('a',20));
  my_map.insert(std::make_pair('a',30));
  my_map.insert(std::make_pair('a',40));
  my_map.insert(std::make_pair('b',10));
  my_map.insert(std::make_pair('c',10));
  my_map.insert(std::make_pair('c',20));
  std::cout << my_map.size() << std::endl;
  std::pair<std::map<char,int>::iterator,std::map<char,int>::iterator> ret;
  ret=my_map.equal_range('a');
  for(std::map<char,int>::iterator it=ret.first;it !=ret.second;it++){
        std::cout << it->first << " => " << it->second << '\n';
  }
  return 0;
}

输出:

3
a => 10

find

find函数里面有三个参数,find(begin,end,value)
前两个是迭代器,是容器的开始和结尾,后一个是所要查找的值

即在容器[begin, end)区间内,寻找是否有指定的value值的元素,如果有,返回该元素的迭代器,没有则返回end;所以find返回值也是一个迭代器;

看一下find的底层实现

find

可以看出来,find内部其实是通过一个for循环来执行的;

实例:

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

int main() {
	vector<int> vec;
	for (int i = 1; i < 11; ++i) vec.push_back(i);
	vector<int>::iterator it = find(vec.begin(), vec.end(), 6);
	if (it != vec.end()) {
		cout << "找到了" << *it << "这个数,下标为:" << it - vec.begin() << endl;
	}
	else {
		cout << "没有找到该数" << endl;
	}
	return 0;
}

find_if

find_if 就是按条件查找元素,就是把vaule换成了一个判断条件,通过这个条件找相应的数;

find_if(iterator begin, iterator end, _Pred);

找到返回指定位置迭代器,找不到返回结束迭代器位置,begin是开始迭代器,end是结束迭代器,_Pred是 函数或者谓词(返回bool类型的仿函数)

实例:

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

bool greaterSix (int n) {
	return n > 6;
} 
int main() {
	vector<int> vec;
	for (int i = 1; i < 11; ++i) vec.push_back(i);
	vector<int>::iterator it = find_if(vec.begin(), vec.end(), greaterSix);
	if (it != vec.end()) {
		cout << "找到了" << *it << "这个数大于6,下标为:" << it - vec.begin() << endl;
	}
	else {
		cout << "没有找到该数" << endl;
	}
	/*auto iit = upper_bound(vec.begin(), vec.end(), 6);
	if (iit != vec.end()) {
		cout << "找到了" << *iit << "这个数大于6,下标为:" << it - vec.begin() << endl;
	}
	else {
		cout << "没有找到该数" << endl;
	}*/
	return 0;
}

在代码中注释的部分,使用了函数upper_bound,这个函数功能和用例里的find_if实现一样,都是找大于6的数,返回的也是迭代器。

find_if 的第三个参数也就是判断条件我们是可以通过 函数 或者 仿函数 自己随意定义的,这就相对于upper_bound会有更多样的判断形式;而upper_bound的底层实现是二分法,这比 find_if 的单纯for循环效率要高。所以要根据不同情况使用不同的算法函数。

adjacent_find

adjacent_find 可以查找相邻重复元素,并返回第一个元素的迭代器,找不到返回end
函数原型:adjacent_find(iterator begin, iterator end);

看一下底层实现:

adjacent_find

就是一个 while 循环不断更新 next 和 first,next 是 first 的下一个元素,直到 next 和 first 相等时返回 first,如果没有找到就返回了 last

实例:

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

int main() {
	vector<int> vec;
	vec.push_back(1);
	vec.push_back(3);
	vec.push_back(4);
	vec.push_back(4);
	vec.push_back(5);
	vector<int>::iterator it = adjacent_find(vec.begin(), vec.end());
	if (it != vec.end()) {
		cout << "找到了重复元素" << *it << ",第一个下标为:" << it - vec.begin() << endl;
	}
	else {
		cout << "没有找到该重复元素" << endl;
	}
	return 0;
}

find_first_of和find_last_of

  • find_first_of 找第一个符合条件的位置
  • find_last_of 找最后一个符合条件的位置

以find_first_of为例

find_first_of 有两种形式:

InputIterator find_first_of (InputIterator beg, InputIterator end,
                             ForwardIterator searchBeg, ForwardItrerator searhcEnd)
 
InputIterator find_first_of (InputIterator beg, InputIterator end,
                             ForwardIterator searchBeg, ForwardItrerator searhcEnd,
                             BinaryPredicate op)
  1. 无op版本,返回同时在区间[beg,end)和[sbeg,send)出现的第一个元素位置的迭代器,同时我们可以采用逆向迭代器获得最后一个元素,未发现则end
  2. 有op版本,返回区间[beg,end)中第一个能与[sbeg,send)内其中一个元素使得op(elem,selem)为真的元素位置的迭代器,未发现则end
  3. 注意, op 不应在函数调用过程中改变状态 (state)。
  4. op 不应改动传入的实参。
  5. 你可以使用 reverse iterator 查找最后一个符合条件的元素。
  6. 复杂度:线性。至多比较(或调用 op())共 numElems * numSearchElems 次。

op推荐采用lambdas表达式:lambdas的使用方法

实例1:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
	//寻找第一个同时在c1,c2出现的元素
	vector<int>c1 = {1,2,3,4,5,6,7,8,9 };
	vector<int>c2 = {3,4,5,6,7};

	auto it = find_first_of(c1.begin(), c1.end(), c2.begin(), c2.end());
	if (it != c1.end())
		//返回满足条件的元素距离首部的距离
		cout << distance(c1.begin(),it)+1<< endl; 
	else
		cout << "未发现" << endl;
}

实例2:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
	//寻找最后一个同时在c1,c2出现的元素
	vector<int>c1 = {1,2,3,4,5,6,7,8,9 };
	vector<int>c2 = {3,4,5,6,7};

	auto it = find_first_of(c1.rbegin(), c1.rend(), c2.begin(), c2.end());
	if (it != c1.rend())
	    //返回满足条件的元素距离首部的距离
		cout << distance(c1.begin(),it.base())<< endl;
	else
		cout << "未发现" << endl;
}

实例3:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
bool oopp(int x,int y){
	if(x>6&&y>6&&x==y) return true;
	else return false;
}
int main()
{
	//寻找第一个同时在c1,c2出现的元素且该元素大于6 
	vector<int>c1 = {1,2,3,4,5,6,7,8,9 };
	vector<int>c2 = {5,6,10,9,8};

	auto it = find_first_of(c1.begin(), c1.end(), c2.begin(), c2.end(),oopp);
	if (it != c1.end())
		//返回满足条件的元素距离首部的距离
		cout << distance(c1.begin(),it)+1<< endl; 
	else
		cout << "未发现" << endl;
}

实例4:

示例代码中使用了两个 vector 容器,制成其他容器也是可以的。只要元素的数据类型一致,可以做 == 操作就行。

另外,代码中还演示了 两个 Vector 合并 Insert() 的用法,以及使用 for_each() 打印元素的用法。

#include <iostream>
#include <algorithm>
int main() {
    std::vector<int> vt1{1,2,3,4,5,6,7,8,9,10};
    std::vector<int> vt2{0,2,6,9};
 
    std::cout << "container 1: ";
    for_each(vt1.cbegin(), vt1.cend(), [](int elem){std::cout << elem << ' ';});
    std::cout <<std::endl;
    std::cout << "container 2: ";
    for_each(vt2.cbegin(), vt2.cend(), [](int elem){std::cout << elem << ' ';});
    std::cout <<std::endl;
    std::vector<int>::iterator pos;
    pos = std::find_first_of(vt1.begin(), vt1.end(), vt2.begin(), vt2.end());
    
    if (pos != vt1.end())
    {
        std::cout << "first element of vt2 in vt1 is element: " << std::distance(vt1.begin(), pos) + 1;
        vt1.insert(vt1.end(), vt2.begin(), vt2.end());
        std::cout <<std::endl;
        
        std::cout << "container 1: ";
        for_each(vt1.cbegin(), vt1.cend(), [](int elem){std::cout << elem << ' ';});
        std::cout <<std::endl;
    }
}

下面的代码片段是使用 reverse iterator 的示例:

std::vector<int>::reverse_iterator rpos;
rpos = std::find_first_of(vt1.rbegin(), vt1.rend(), vt2.begin(), vt2.end());
std::cout<< "last element of vt2 in vt1 is element:" << std::distance(vt1.begin(), rpos.base());

count 和 count_if

count
可以统计元素个数,返回值为 int 类型,
函数原型:count(iterator beg, iterator end, value);
前两个参数规定了区间,最后一个所需要统计的元素;
底层实现非常简单,就是一个for循环遍历区间,找到一个元素加一,直到结束,所以效率也不是特别高
count_if
这个是在统计一个元素个数的前提下加入了条件,就是按条件统计元素个数,返回值是 int 类型;
函数原型:count_if(iterator beg, iterator end, _Pred);
前两个参数还是规定的区间,最后一个是一个谓词(即仿函数)或者函数

实例:

#include <iostream>
#include <algorithm>
#include <vector>
int main ()
{
  std::vector<int> vec = {2, 4, 4, 4, 7, 9};
  int numFours = std::count(vec.begin(), vec.end(), 4);
  std::cout << "元素 4 出现了 " << numFours << " 次。";
  return 0;
}

search

std::search 用于在一个序列中搜索另一个子序列的第一次出现。

实例:

#include <iostream>
#include <algorithm>
#include <vector>
int main ()
{
std::vector<int> mainSeq = {4, 7, 2, 9, 5};
std::vector<int> subSeq = {7, 2};

auto it = std::search(mainSeq.begin(), mainSeq.end(), subSeq.begin(), subSeq.end());

if (it != mainSeq.end()) {
    std::cout << "子序列在主序列中找到了!";
} else {
    std::cout << "未找到子序列。";
}
return 0;
}

min_element()和max_element()

std::min_element()的使用方法:

  • 查找一个区间内的最小元素:std::min_element(first, last)
  • 查找一个区间内的最小元素,并使用自定义比较函数:std::min_element(first, last, comp)

std::max_element()的使用方法:

  • 查找一个区间内的最大元素:std::max_element(first, last)
  • 查找一个区间内的最大元素,并使用自定义比较函数:std::max_element(first, last, comp)

其中,first和last分别是容器的起始迭代器和终止迭代器,comp是一个可调用对象,用于比较两个元素的大小关系。如果不指定comp,则默认使用<运算符进行比较。

注意:std::min_element()和 std::max_elenent() 返回的是迭代器,指向容器中的最小元素和最大元素。如果需要获取元素的值,可以使用( 运算符对迭代器进行解引用。

实例:

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
    auto min_it = std::min_element(v.begin(), v.end()); // 查找最小元素
    auto max_it = std::max_element(v.begin(), v.end()); // 查找最大元素
    cout<<"最小元素:"<<*min_it<<endl;
    cout<<"最大元素:"<<*max_it<<endl;
    return 0;
}

当然,简单的可以使用min和max

#include <iostream>
#include <algorithm>
int main() {
    int p = 18;
    int q = 22;
    int r = 15;
    std::cout <<"比较p和q两个值"<< std::endl;
    std::cout <<"较大值"<<std::max(p,q)<< std::endl;
    std::cout <<"较小值"<<std::min(p,q)<< std::endl;
    int max_of_three = std::max({p, q, r});
    int min_of_three = std::min({p, q, r});
    std::cout << "Max of three: " << max_of_three << std::endl;
    std::cout << "Min of three: " << min_of_three << std::endl;
    return 0;
}

参考博文:

https://blog.csdn.net/YXXXYX/article/details/119866219

https://blog.csdn.net/YXXXYX/article/details/119908496

https://blog.csdn.net/qq_34462436/article/details/108105395

https://blog.csdn.net/qq_66726657/article/details/134475023

https://blog.csdn.net/BTChioa/article/details/134960749

https://blog.csdn.net/kingkee/article/details/103806681

https://blog.csdn.net/weixin_44806268/article/details/105834016

https://blog.csdn.net/weixin_43305485/article/details/122347842

  • 15
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值