C++ STL容器篇(三) day14

C++ STL容器篇(三) day14

STL(initializer_list)

  • initializer_list就是列表,就是{}数据
  • 每当函数签名需要 initializer_list 时,编译器将具有同类元素的大括号内的初始值设定项列表转换为 initializer_list。
#include 
#include 
#include 

void testInitializer_list()
{
	std::initializer_list<int> ini{ 1,2,3,4,5,6 };
	std::vector<int> ve{ 1,2,3,4,5 }; 
	for (auto v : ini)
	{
		std::cout << v << " ";
	}
	std::cout << std::endl;
}
//自己写列表
namespace My{
	template <class _Ty> class vector
	{
	public:
		vector(int size)
		{
			this->p_size = size;
			this->p_memory = new _Ty[p_size];
		}
		//传入一个列表就可以实现自己写的vector赋值初始化操作
		vector(const std::initializer_list<_Ty>& num)
		{
			this->p_size = num.size();
			this->p_memory = new _Ty[p_size];
			int i = 0;
			for (auto v : num)
			{
				this->p_memory[i++] = v;
			}
		}
		//重载一下begin和end函数就可以区间遍历
		_Ty* begin()
		{
			return p_memory;
		}
		_Ty* end()
		{
			return p_memory + p_size;
		}
	protected:
		_Ty* p_memory;
		size_t p_size;
	};
}

int main()
{
	My::vector<int> ve(5);
	My::vector<int> ve2 = { 1,2,3,4,5 };
	for (auto v : ve2)
	{
		std::cout << v << " ";
	}
	std::cout << std::endl;
	testInitializer_list();
	return 0;
}

STL(set)

  • C++集合有以下三个:
    • bitset:二进制集合
    • set:单集合
    • multiset:多重集合

二进制集合bitset

  • 专门用来处理二进制的
  • 具体库函数查看官方手册,bitset官方手册
    • all 测试此 bitset 中的所有位以确定它们是否都设置为 true。
    • any 成员函数测试序列中是否有任何位设置为 1。
    • count 成员函数返回位序列中设置的位数。
    • flip 反转 bitset 中的所有位的值或反转位于指定位置的单个位。
    • none 测试 bitset 对象中是否不存在任何已设置为 1 的位。
    • reset 将 bitset 中的所有位重置为 0 或将位于指定位置的位重置为 0。
    • set 将 bitset 中的所有位设置为 1 或将位于指定位置的位设置为 1。
    • size 返回 bitset 对象中的位数。
    • test 测试 bitset 中指定位置处的位是否设置为 1。
    • to_string 将 bitset 对象转换为字符串表示形式。
    • to_ullong 将 bitset 中的位值的总和作为 unsigned long long 返回。
    • to_ulong 将 bitset 对象转换为 unsigned long,如果将后者用于初始化 bitset,则会产生包含的位的序列。
#include 
#include 
void testBitset() 
{
	std::bitset<8> bit1;
	std::bitset<8> bit2("10010101");
	std::cout << bit2 << std::endl;
	//取反
	bit2.flip();
	std::cout << bit2 << std::endl;
	std::cout <<"判定是否存在1:" << bit2.any() << std::endl;
	std::cout << "判断是否都是1:" << bit2.all() << std::endl;
	std::cout << bit2.to_ulong() << std::endl;
}
int main() 
{
	testBitset();
	return 0;
}

单集合set

  • 单集合具有有序性与去重性
  • 具体库函数查看官方手册,set官方手册
    • begin 返回一个迭代器,此迭代器用于发现 set 中的第一个元素。
    • cbegin 返回一个常量迭代器,此迭代器用于发现 set 中的第一个元素。
    • cend 返回一个常量迭代器,此迭代器用于发现 set 中最后一个元素之后的位置。
    • clear 清除 set 的所有元素。
    • contains 检查 set 中是否包含具有指定键的元素。
    • count 返回 set 中其键与指定为参数的键匹配的元素数量。
    • crbegin 返回一个常量迭代器,此迭代器用于发现反向 set 中的第一个元素。
    • crend 返回一个常量迭代器,此迭代器用于发现反向 set 中最后一个元素之后的位置。
    • emplace 将就地构造的元素插入到 set。
    • emplace_hint 将就地构造的元素插入到 set,附带位置提示。
    • empty 测试 set 是否为空。
    • end 返回一个迭代器,此迭代器用于发现 set 中最后一个元素之后的位置。
    • equal_range 返回一对迭代器,这两个迭代器分别用于发现 set 中其键大于指定键的第一个元素,以及 set 中其键等于或大于指定键的第一个元素。
    • erase 从集中的指定位置移除一个元素或元素范围,或者移除与指定键匹配的元素。
    • find 返回一个迭代器,此迭代器用于发现 set 中其键与指定键等效的元素的位置。
    • get_allocator 返回用于构造 allocator 的 set 对象的副本。
    • insert 将一个元素或元素范围插入到 set。
    • key_comp 检索用于对 set 中的键进行排序的比较对象副本。
    • lower_bound 返回一个迭代器,此迭代器指向集中其键等于或大于指定键的第一个元素。
    • max_size 返回 set 的最大长度。
    • rbegin 返回一个迭代器,此迭代器用于发现反向 set 中的第一个元素。
    • rend 返回一个迭代器,此迭代器用于发现反向 set 中最后一个元素之后的位置。
    • size 返回 set 中的元素数量。
    • swap 交换两个 set 的元素。
    • upper_bound 返回一个迭代器,此迭代器指向 set 中其键大于指定键的第一个元素。
    • value_comp 检索用于对 set 中的元素值进行排序的比较对象副本。
#include 
#include 
#include 

class student
{
public:
	student(std::string name = "", int age = 0) :name(name), age(age) {}
	//重载<
	bool operator<(const student& xiaogua) const
	{
		return this->age < xiaogua.age;
	}
	//共有接口
	std::string getName() const { return name; };
	int getAge() const { return age; };
protected:
	std::string name;
	int age;
};
//重载排序方法,按照名字从大到小
class customBysort
{
public:
	bool operator()(const student& xiaogua,const student& dagua) const
	{
		return xiaogua.getName() > dagua.getName();
	}
};

void tsetSet()
{
	//默认排序准则less
	std::set<int> se{ 1,2,3,4,6,6,8,2,5,7 };
	for (auto v : se)
	{
		std::cout << v << " ";
	}
	std::cout << std::endl;
	//从大到小
	std::set<int, std::greater<int>> se2 = { 1,2,3,4,6,6,8,2,5,7 };
	for (auto v : se2)
	{
		std::cout << v << " ";
	}
	std::cout << std::endl;
}
//操作自定义类型,需要重载less方法
void operationSet()
{
	std::set<student> se;
	se.insert(student("3小瓜", 21));
	se.insert(student("1大瓜", 23));
	se.insert(student("2傻瓜", 22));
	for (auto v : se)
	{
		std::cout << v.getName() << " " << v.getAge();
		std::cout << std::endl;
	}
	std::cout << std::endl;

	std::cout << "自定义排序:" << std::endl;
	std::set<student, customBysort> se2;
	se2.insert(student("1小瓜", 21));
	se2.insert(student("3大瓜", 23));
	se2.insert(student("2傻瓜", 22));
	for (auto v : se2)
	{
		std::cout << v.getName() << " " << v.getAge();
		std::cout << std::endl;
	}
	//删除,根据迭代器做删除
	auto iter = find_if(se2.begin(), se2.end(),
		[](const student& object) {return object.getName() == "1小瓜"; });
	if (iter != se2.end())
	{
		se2.erase(iter);
	}
	std::cout <<  std::endl;
	//std::set::iterator it
	for (auto it = se2.begin(); it != se2.end(); it++)
	{
		std::cout << (*it).getName() << "\t" << (*it).getAge() << std::endl;
	}
}
int main()
{
	tsetSet();
	operationSet();
	return 0;
}

多重集合multiset

  • 多重集合可以重复没有去重性,其他操作和性质与set一模一样
  • 具体查看官方手册即可,multiset官方手册

STL(映射)

  • 形如y=x这种关系就叫映射
void tsetPair()
{
	std::pair<int,std::string> pa;
	pa.first = 1;//键
	pa.second = "value";//值
}

STL(map)

  • map具有排序性(按照键做排序),键唯一性
  • 注意map里面的删除用find_if查找的时候Lambda表达式里面传的类型是容器的数据类型
    • 否则会报错,提示这里是容器的数据类型,就要传数据存的类型
      C++ STL容器篇(三) day14_第1张图片
      C++ STL容器篇(三) day14_第2张图片
    • 改正
      C++ STL容器篇(三) day14_第3张图片
  • map的成员函数也很多但是也和集合差不多,具体查找官方手册即可,map官方手册
#include 
#include 
#include 

void testMap()
{
	//单映射
	std::map<int, std::string> ma;
	//插入,键相同不做插入
	//方法1:insert直接插入,利用pair构造一个对象进行插入
	ma.insert(std::pair<int, std::string>(1, "小瓜"));
	//方法2:调用make_pair可以间接创建数对对象
	ma.insert(std::make_pair<int, std::string>(2, "大瓜"));
	//方法3:直接数组下标法,键就是下标
	ma[3] = "傻瓜";
	ma[4] = "呆瓜";
	ma[-1] = "木瓜";
	std::cout << "区间遍历:" << std::endl;
	for (auto v : ma)
	{
		std::cout << v.first << " " << v.second << std::endl;
	}
	std::map<std::string, std::string> strma;
	strma["小瓜"] = "大黄瓜";
	strma["大瓜"] = "大西瓜";
	strma["傻瓜"] = "大冬瓜";
	std::cout << "迭代器遍历:" << std::endl;
	std::map<std::string, std::string>::iterator it;
	for (it = strma.begin(); it != strma.end(); it++)
	{
		std::cout << (*it).first << " " << it->second << std::endl;
	}

}

class student
{
public:
	student(std::string name = " ", int age = 0) :name(name), age(age) {}
	std::string getName()const { return this->name; };
	int getAge() const { return this->age; };
protected:
	std::string name;
	int age;
};

//自定义比较准则
class CustomSort
{
public:
	bool operator()(const student& xiaogua, const student& dagua) const
	{
		return xiaogua.getAge() < dagua.getAge();
	}
};

void customByOperation()
{
	std::map<int, student> ma1;//一般这种就没必要写自定义排序准则,因为是按键排序
	std::map<student, student,CustomSort> ma2;//这个就需要自定义排序准则
	ma2[student("小瓜", 21)] = student("小美", 23);
	ma2[student("大瓜", 23)] = student("大美", 21);
	ma2[student("傻瓜", 22)] = student("傻美", 22);
	for (auto v : ma2)
	{
		std::cout << v.first.getName() << " " << v.first.getAge() <<" "<<
			v.second.getName() << " " << v.second.getAge() << std::endl;
	}
	std::cout << std::endl << "删除21和23:" << std::endl;
	//删除
	//如果这里是要删除用户输入的,那么这个Lambda表达式要用引用,
	//这里应该传容器里面的数据类型
	auto it = find_if(ma2.begin(), ma2.end(), 
		[](const std::pair<const student, student>& object) {return object.first.getAge() == 21; });
	if (it != ma2.end())
	{
		ma2.erase(it);
	}
	//也可以自动推断类型
	auto it2 = find_if(ma2.begin(), ma2.end(),
		[](const auto& object) {return object.first.getAge() == 23; });
	if (it2 != ma2.end())
	{
		ma2.erase(it2);
	}
	for (auto v : ma2)
	{
		std::cout << v.first.getName() << " " << v.first.getAge() << " " <<
			v.second.getName() << " " << v.second.getAge() << std::endl;
	}
}


int main()
{
	testMap();
	std::cout << std::endl;
	customByOperation();
	return 0; 
}
  • 运行结果
    C++ STL容器篇(三) day14_第4张图片

STL(multimap)

  • multimap是多重映射,键不唯一,只具有排序性,所以它不能直接通过下标法插入.
  • 和map操作差不多,只是没有键的唯一性,可以重复插入相同的
  • 具体成员函数查看手册,multimap官方手册
#include 
#include 
#include 

void testMap()
{
	//多重映射
	std::multimap<int, std::string> ma;
	ma.insert(std::make_pair(21, "小瓜"));
	ma.insert(std::make_pair(23, "大瓜"));
	ma.insert(std::make_pair(22, "傻瓜"));
	for (auto v : ma)
	{
		std::cout << v.first << " " << v.second << std::endl;
	}
}


class student
{
public:
	student(std::string name = " ", int age = 0) :name(name), age(age) {}
	std::string getName()const { return this->name; };
	int getAge() const { return this->age; };
protected:
	std::string name;
	int age;
};

//自定义比较准则
class CustomSort
{
public:
	bool operator()(const student& xiaogua, const student& dagua) const
	{
		return xiaogua.getAge() < dagua.getAge();
	}
};

void customByOperation()
{

	std::multimap<student, student,CustomSort> ma2;//这个就需要自定义排序准则
	ma2.insert(std::make_pair(student("小瓜", 21), student("小美", 23)));
	ma2.insert(std::make_pair(student("大瓜", 23), student("大美", 21)));
	ma2.insert(std::make_pair(student("傻瓜", 22), student("傻美", 22)));

	for (auto v : ma2)
	{
		std::cout << v.first.getName() << " " << v.first.getAge() <<" "<<
			v.second.getName() << " " << v.second.getAge() << std::endl;
	}
	std::cout << std::endl << "删除21和23:" << std::endl;
	//删除
	//如果这里是要删除用户输入的,那么这个Lambda表达式要用引用,
	//这里应该传容器里面的数据类型
	auto it = find_if(ma2.begin(), ma2.end(), 
		[](const std::pair<student,student>& object) {return object.first.getAge() == 21; });
	if (it != ma2.end())
	{
		ma2.erase(it);
	}
	//也可以自动推断类型
	auto it2 = find_if(ma2.begin(), ma2.end(),
		[](const auto& object) {return object.first.getAge() == 23; });
	if (it2 != ma2.end())
	{
		ma2.erase(it2);
	}
	for (auto v : ma2)
	{
		std::cout << v.first.getName() << " " << v.first.getAge() << " " <<
			v.second.getName() << " " << v.second.getAge() << std::endl;
	}
}


int main()
{
	testMap();
	std::cout << std::endl;
	customByOperation();
	return 0; 
}

拓展:map结合单列设计模式管理资源

  • 简易使用map与单利设计模式结合EasyX管理图片资源
  • 本次采用多文件写法,新建一个资源resource头文件与其实现的cpp
  • 项目属性设置为多字节字符集,因为要使用EasyX

resource.h

#pragma once
#include //图形库头文件
#include 
#include 
#include 
#include 
#include 
#include 
//单例设计模式
class ResourceImage
{
public:
	~ResourceImage();//析构函数
	//提供一个静态创建接口
	static ResourceImage* GetReource();
	static std::map<std::string, IMAGE*> SingleFrameImg;//单帧图片
	static std::map<std::string, std::pair<int, IMAGE*>> multiframe;//多帧图片
	static void ShowSingleFrameImg(int x, int y, std::string name);
	static void ShowMultiframe(int x, int y, std::string name,int frame);

private:
	//构造函数私有化
	ResourceImage();
};

resource.cpp

#include "resource.h"

std::map<std::string, IMAGE*> ResourceImage::SingleFrameImg;
std::map<std::string, std::pair<int, IMAGE*>> ResourceImage::multiframe;

//析构函数
ResourceImage::~ResourceImage()
{
}
//创建唯一的对象
ResourceImage* ResourceImage::GetReource()
{
	static ResourceImage* res = new ResourceImage;
	return res;
}
//显示背景
void ResourceImage::ShowSingleFrameImg(int x, int y, std::string name)
{
	putimage(x, y, GetReource()->SingleFrameImg[name]);

}
//显示动作
void ResourceImage::ShowMultiframe(int x, int y, std::string name,int frame)
{
	//位图宽度是3200/8就是400等于每一帧的图片
	putimage(x, y, 400, 300, GetReource()->multiframe[name].second + 0, frame * 400, 0, SRCAND);
	putimage(x, y, 400, 300, GetReource()->multiframe[name].second + 1, frame * 400, 0, SRCPAINT);
}

//构造函数
ResourceImage::ResourceImage()
{
	//因为是IMAGE* 所以要new一下内存
	SingleFrameImg["背景"] = new IMAGE;
	loadimage(SingleFrameImg["背景"],"./resource/凌华.jpg");//加载图像

	multiframe["夏洛特"].first = 8;//存的帧数
	multiframe["夏洛特"].second = new IMAGE[2];
	loadimage(multiframe["夏洛特"].second + 0, "./resource/lefty.bmp");
	loadimage(multiframe["夏洛特"].second + 1, "./resource/left.bmp");

}

main.cpp

#include "resource.h"
//创建一个定时器
bool CreateTimer(int duration)
{
	//注意定时器的开始时间要加static
	static int beginTime = clock();
	int endTime = clock();
	if (endTime - beginTime > duration)
	{
		beginTime = endTime;
		return true;
	}
	return false;
}
int main()
{
	initgraph(1000, 832, 1);
	ResourceImage::ShowSingleFrameImg(0, 0, "背景");
	BeginBatchDraw();
	bool isKey = false;
	int frame = 0;
	while (true)
	{
		cleardevice();
		ResourceImage::ShowSingleFrameImg(0, 0, "背景");
		ResourceImage::ShowMultiframe(900-200, 400-150, "夏洛特", frame);
		FlushBatchDraw();
		if (_kbhit())
		{
			if (_getch() == ' ') //是否按下空格
			{
				isKey = true;
			}
			else
			{
				isKey = false;
			}
		}
		if (isKey == true && CreateTimer(50))
		{
			frame++;
			std::cout << "frame:" << frame << std::endl;
			if (frame >= 8)
			{
				isKey = false;
				frame = 0;
				std::cout << "--------------------------" << std::endl;
			}
		}
	}
	EndBatchDraw();
	while (true);
	closegraph();
	return 0;
}
  • 运行结果
    C++ STL容器篇(三) day14_第5张图片

你可能感兴趣的:(励志学习C瓜瓜,c++,windows,开发语言,学习,笔记)