C++ STL算法基础与迭代器 day16

C++ STL算法基础与迭代器 day16

C++迭代器

  • 迭代器是一个类中类,通过实现运算符重载实现对象模仿指针的行为对容器进行遍历
  • 迭代器类型分为:
    • 正向迭代器:容器名::iterator iter
      • begin();
      • end();
    • 反向迭代器:容器名::reverse_iterator iter
      • rbegin();
      • rend();
    • 常正向迭代器:容器名::const_iterator iter
      • cbegin();
      • end();
    • 常反向迭代器:容器名::const_reverse_iteraor iter
      • crbegin();
      • crend();
  • 迭代器功能分为:
    • 正向迭代器
    • 反向迭代器
    • 随机访问迭代器
容器迭代器类型
array,vector,deque随机
list,set,mutiset,map,multiset双向
stack,queue,priority_queue不支持
  • 迭代器辅助函数
//迭代器位移
 void advance(_InIt& _Where, _Diff _Off);
//测试迭代器的距离长度也就是容器的元素个数
_Iter_diff_t<_InIt> distance(_InIt _First, _InIt _Last);
//交换容器的两个元素
void iter_swap(_FwdIt1 _Left, _FwdIt2 _Right) 
#include <iostream>
#include <vector>
#include <list>

int main()
{
	std::list<int> myList = { 1,2,3,4,5,7 };
	std::vector<int> vec = { 1,2,3,4,5,6 };
	//列表不是连续的内存所以需要调用advance函数来进行迭代器偏移
	auto iterList = myList.begin();
	std::advance(iterList, 3);
	std::cout << *iterList << std::endl;
	//而vector是连续的内存,所以可以直接迭代器偏移
	auto iterVec = vec.begin() + 3;
	std::cout << *iterVec << std::endl;
	//distance获取迭代器距离(容器元素个数)
	std::cout << std::distance(vec.begin(), vec.end()) << std::endl;
	//iter_swap交换容器的两个元素
	iter_swap(vec.begin(), vec.begin() + 3);
	for (auto v : vec)
	{
		std::cout << v << " ";
	}
	return 0;
}
  • 运行结果
    在这里插入图片描述
  • 流型迭代器
    • 输入流迭代器
      • istream_iteraot<type> object EOF流
      • istream_iteraot<type> object(istream& in);
      • *object:等效于cin>>
    • 输出流迭代器
      • ostream_iteraot<type> object(ostream& out)
      • ostream_iteraot<type> object(ostream& out,const char* str);
      • object=value; 等效于把数据打印到屏幕上 cout<<valure
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
#include <functional>

int main()
{
	std::vector<int> vec = { 1,2,3,4,5 };
	//构造方法一
	std::ostream_iterator<int> object(std::cout);
	object = 123;
	std::cout << std::endl;
	for (auto v : vec)
	{
		object = v;
	}
	std::cout << std::endl;

	//构造方法二提供了一个字符串,相当于可以自行添加一个字符进去
	std::ostream_iterator<int> object2(std::cout, " ");
	for (auto v : vec)
	{
		object2 = v;
	}
	std::cout << std::endl;

	//结合copy算法实现容器遍历
	std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>(std::cout, " "));
	std::cout << std::endl;

	//采样输入流进行输入,输入出错就会返回一个EOF的错误
	std::cout << "不输入数字就会结束输入:" << std::endl;
	std::istream_iterator<int> Eof;
	std::istream_iterator<int> in(std::cin);
	std::vector<int> input;
	while (in != Eof)
	{
		input.push_back(*in);
		in++;
	}
	for (auto v : input)
	{
		std::cout << v << " ";
	}
	std::cout << std::endl;
	return 0;
}
  • 运行结果
    在这里插入图片描述

C++仿函数

  • 仿函数就是类模仿函数的行为
  • 仿函数重点在于重载()运算符
  • 通常仿函数大部分情况都是比较准则
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
#include <functional>
//自己写仿函数
struct Sum
{
	int operator()(const int& a, const int& b)
	{
		return a + b;
	}
};
void testFun()
{
	Sum object;
	std::cout << object.operator()(1, 2) << std::endl;
	std::cout << object(1, 2) << std::endl;
	//{}帮助解析,先构造一个无名对象,然后通过对象调用重载函数
	std::cout << Sum{}(1, 2) << std::endl;
}

//自己写标准库里面排序准则的仿函数
namespace mySort
{
	//_Pr:谓词
	template<typename _Ty,typename _Pr>
	void sort(_Ty arr[], int size)
	{
		for (int i = 0; i < size; i++)
		{
			for (int j = 0; j < size - i - 1; j++)
			{
				if (_Pr{}(arr[j], arr[j + 1]) == false)
				{
					_Ty temp = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = temp;
				}
			}
		}
	}
	//排序准则
	template<typename _Ty>
	struct less
	{
		bool operator()(const _Ty& a, const _Ty& b) const
		{
			return a < b;
		}
	};
	template<typename _Ty>
	struct greater
	{
		bool operator()(const _Ty& a, const _Ty& b) const
		{
			return a > b;
		}
	};
}


int main()
{
	testFun();
	int arr[6] = { 1,3,5,6,2,4 };
	mySort::sort<int, mySort::less<int>>(arr, 6);
	for (auto v : arr)
	{
		std::cout << v << " ";
	}
	std::cout << std::endl;

	mySort::sort<int, mySort::greater<int>>(arr, 6);
	for (auto v : arr)
	{
		std::cout << v << " ";
	}
	std::cout << std::endl;

	//标准库中sort
	std::sort(arr, arr + 6, std::less<int>());
	for (auto v : arr)
	{
		std::cout << v << " ";
	}
	std::cout << std::endl;

	std::sort(arr, arr + 6, std::greater<int>());
	for (auto v : arr)
	{
		std::cout << v << " ";
	}
	std::cout << std::endl;
	return 0;
}
  • 运行结果
    在这里插入图片描述
  • 标准库中的仿函数特别多,这里就少例举一些
//标准库中的仿函数
#include <iostream>
#include <set>
#include <functional>
#include <algorithm>
//标准库中的仿函数
void stdFunctional() 
{
	//算术
	std::cout << std::plus<int>{}(1, 2) << std::endl;
	//关系
	std::cout << std::greater_equal<int>{}(1, 2) << std::endl;
	//逻辑类
	std::cout << std::logical_and<int>{}(1, 0) << std::endl;
	//位运算
	std::cout << std::bit_and<int>{}(1, 1) << std::endl;
	//.....
}

int main() 
{
	stdFunctional();
	return 0;
}
  • 运行结果
    在这里插入图片描述

C++函数包装器

  • 函数包装器就是把函数指针包装成为一个对象,通过运算符重载实现对象去调用函数
  • 包装方法
    • function <函数返回值类型(参数类型)> object(函数指针);
  • 使用方法
    • object(参数);
#include <iostream>
#include <algorithm>
#include <functional>

int sum(int a, int b)
{
	return a + b;
}
class Fun
{
public:
	int operator()(int a,int b) 
	{
		return a + b;
	}
	//使用静态数据,访问可以不需要对象避免一些麻烦
	static void product(int a, int b, int c)
	{
		std::cout << a * b * c << std::endl;
	}
	//using语法
	using PFUNC = void(*)(int, int, int);
	运算符重载隐式转换
	operator PFUNC()
	{
		//返回函数指针
		return product;
	}
};
void testFunction()
{
	//包装普通函数
	std::function<int(int, int)> pSum(sum);
	std::cout << pSum(1, 2) << std::endl;
	//包装仿函数
	Fun fun;
	std::function<int(int, int)> func = fun;
	std::cout << func(1, 2) << std::endl;
	//原生的成员函数指针
	int(Fun:: * pFunc)(int, int) = &Fun::operator();
	std::cout << (fun.*pFunc)(1, 2) << std::endl;
	//包装对象做隐式转换指针
	std::function<void(int, int, int)> func2 = fun;
	func2(1, 2, 3);
	//无法包装类中成员函数
}
int main()
{
	testFunction();
	return 0;
}
  • 运行结果
    在这里插入图片描述

C++函数适配器

  • 函数适配器就是绑定默认参数,实现函数指针特定调用方法,一般是为了适应别人提供的接口
#include <iostream>
#include <functional>

void print(int a, int b, int c)
{
	std::cout << a << " " << b << " " << c << std::endl;
}

//别人提供的接口
template <typename _Pr>
void printData(_Pr pr, int a, int b)
{
	//别人提供的调用只能用两个参数
	pr(a, b);
}

void Bind()
{
	//placeholders占位符
	auto pFunc = std::bind(print, std::placeholders::_1, std::placeholders::_2, 0);
	print(1, 2, 3);
	pFunc(1, 2);
	//适配器提供了默认参数,传参就无效了
	pFunc(1,2,3);
	//通过适配器绑定默认参数,就可以调用提供的接口
	printData(pFunc, 1, 2);
}
int main()
{
	Bind();
	return 0;
}

  • 运行结果
    在这里插入图片描述
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>

//别人提供的接口
template <typename _Pr>
void printTest(_Pr pr, int a, int b)
{
	//别人提供的调用只能用两个参数
	pr(a, b);
}

class student
{
public:
	void printData(int a, int b, int c)
	{
		std::cout << a << " " << b << " " << c << std::endl;
	}
};
void testBind()
{
	//绑定类中的成员函数
	student xiaogua;
	//原生函数指针
	void(student:: *p1)(int, int, int) = &student::printData;
	(xiaogua.*p1)(1, 2, 3);
	//绑定类的成员函数的第二个参数是对象的地址
	auto p2 = std::bind(&student::printData, &xiaogua,std::placeholders::_1,2,0);
	p2(1, 2, 3);
	
	auto p3 = std::bind(&student::printData, &xiaogua, std::placeholders::_1,
		std::placeholders::_2, 0);
	printTest(p3, 2, 3);
}

void testCount()
{
	//lambda表达式写法
	std::vector<int> score{ 99,98,97,96,59 };
	std::cout << "及格人数:" << std::count_if(score.begin(), score.end(),
		[](int& data) {return data >= 60; }) << std::endl;
	//仿函数适配接口写法
	std::cout << "及格人数:" << std::count_if(score.begin(), score.end(),
		std::bind(std::greater_equal<int>(), std::placeholders::_1, 60)) << std::endl;
}
int main()
{
	testBind();
	testCount();
	return 0;
}

  • 运行结果
    在这里插入图片描述

适配器与包装器混合使用

  • 适配器具有调整参数功能
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>

class student
{
public:

};
void print(int a, std::string b, student object)
{
	std::cout << __FUNCDNAME__ << std::endl;
}

void test()
{
	auto p1 = std::bind(print,
		std::placeholders::_2,		//调用的时候第二个参数是原函数的第一个参数 (int)
		std::placeholders::_3,		//调用的时候第三个参数是原函数的第二个参数 (std::string)
		std::placeholders::_1);		//调用的时候第一个参数是原函数的第三个参数 (student)

	student xiaogua;
	p1(xiaogua, 21, "小瓜");
	//对应参数类型
	std::function<void(student, int, std::string)> pFunc = p1;
	pFunc(xiaogua, 21, "大瓜");
}
int main()
{
	test();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值