C++ STL标准模板库

standard template libaray标准模板库

一、标准容器
1.顺序容器
vector 向量
deque 双端队列
list 链表
2.容器适配器
stack 栈
queue 队列
priority_queue 优先级队列
3.关联容器
无序关联容器 链式哈希表O(1)
unordered_set 	无序的单重集合
unordered_map	无序的单重映射表
unordered_multiset	无序的多重集合
unordered_multimap	无序的多重映射表
有序关联容器 红黑树 O(log2n)
set	单重集合
multiset	多重集合
map		单重映射表
multimap	多重映射表

二、近容器
数组,string,bitset 位容器(哈夫曼)

三、迭代器
iterator和const_iterator
reverse_iterator和const_reverse_iterator

四、函数对象
greater,less(类似C的函数指针)

五、泛型算法
sort,find,find_if,binary_search,for_each

vector

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

/*
	vector向量容器:底层是动态开辟的数组,每次以原来空间大小的二倍扩容
	增减	
		push_back(20)在末尾添加 O(1) 导致容器扩容 //注意空间配置器
		insert(it,20)在迭代器指向的位置添加元素O(n)
	删除
		pop_back() 末尾删除元素O(1)
		erase(it)	删除迭代器指向的元素O(n)
	查询
		operator[]	中括号运算符重载,下标的随机访问o(1)
		iterator 迭代器
		find,for_each
		foreach通过迭代器实现的
		注意:对容器进行连续插入或删除的操作insert/eraser,一定要更新迭代器,不然会产生迭代器失效问题
	常用方法介绍
		size()返回容器底层有效元素的个数
		empty()判断容器是否为空
		reserve(20) vector 预留空间的 不然扩容太频繁效率低
		resize(20) vector 重置大小的扩容 不止开辟空间 还有添加新的元素
		swap 两个容器进行元素交换
*/

int main()
{
	vector<int> vec;
	for (int i = 0; i < 20; ++i)
	{
		vec.push_back(rand() % 100 + 1);
	}
	int size = vec.size();
	for (int i = 0; i < size; ++i)
	{
		cout << vec[i] << " ";
	}
	cout << endl;

	//删除vector中所有的偶数
	vector<int>::iterator it2 = vec.begin();
	for (; it2 != vec.end();)
	{
		if (*it2 %2 == 0)
		{
			it2 = vec.erase(it2);
		}
		else
		{
			//如果重定位了it2的数值,就不需要++了
			++it2;
		}
	}

	//给所有容器中的奇数前面都添加一个小于奇数1的偶数
	for (it2= vec.begin(); it2 != vec.end();++it2)
	{
	}if (*it2 % 2 != 0)
	{
		it2 = vec.insert(it2, *it2 - 1);
		++it2;
	}


	vector<int>::iterator it1 = vec.begin();
	for (;it1 != vec.end(); ++it1)
	{
		cout << *it1 << " ";
	}
	cout << endl;
	return 0;
}

deque和list

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

/*
	双端队列容器
	动态开辟的二维数组,两端都即是队尾,又是对头
	一维数组从2开始,以2倍的方式进行扩容,
	每次扩容后原来的第二维数组,从新的第一维数组下标oldsize/2开始存放,上下预留相同空白

	deque<int> deq;
	增加:
	deq.push_back(20);		从末尾添加元素O(1)会引起扩容
	deq.push_front(20);		从首部添加元素O(1)
	deq.insert(it,20);		it指向的位置添加元素 O(n)
	删除:
	deq.pop_back()	从末尾删除元素O(1)
	deq.pop_front()	从首部删除元素O(1)
	deq.eraser()	从it指向的位置删除元素O(n)
	查询搜索:
	迭代器(注意迭代器失效问题)

	list
		链表容器,双向循环链表
		和deque完全一致
	insert O(1),元素不移动
	在插入前先查询,query查询操作,查询的效率比较低

*/


int main()
{

}

顺序容器的对比

#include<iostream>
using namespace std;

/*
	vector:动态数组,内存连续,二倍扩容,很长的连续空间 vector<int> vec;
	deque:动态开辟的二维数组空间,第二维是固定长度的数组空间,,一维二倍扩容,每一个二维是连续的
	list:双向循环链表

	vector 和deque之间的区别?
		底层数据结构不同
		前中后插入删除时间复杂度:中间和末尾O(1)  最前面deque O(1)/vector O(n)
		对于内存的使用效率:vector低,随着扩容需要一大片连续的内存空间 deque 可以进行分块进行数据存储,不需要内存空间必须要连续
		insert/erase 中间 时间复杂度都是O(1) vector 方便,因为vector连续


	vector 和list之间的区别?
	什么时候用数组好,什么时候用链表好
	数组:增加删除查询O(n) 随机访问O(1)
	链表:增加删除节点 O(1) 搜索的时间
*/

int main()
{


	return 0;
}

容器适配器

#include <iostream>
#include <deque>
using namespace std;

/*
	设计模式,适配器模式
	标准容器中---容器适配器
	1.适配器底层没有自己的数据结构,他是另外一个容器的封装,它的方法全部由底层依赖的容器来实现
	2.没有实现自己的迭代器
*/

/*
	问题:		stack 为什么不依赖vector			:
				queue 为什么不依赖vector			: vector 初始内存的使用效率太低了 0-1-2-4-8,使用reserve可以
												  对于queue来说,需要支持尾部插入,头部删除O(1)复杂度,但是vector头部达不到,底层出队效率很低
												  vector 需要大片的连续的内存,而queue只需要分段的内存,当存储大量数据时,deque更好一些
		大根堆	priority_queue 为什么依赖vector	: 底层默认把数据组成一个大根堆结构,在一个内存连续的数组上,构建一个大根堆,堆中的每一个节点和左右孩子是根据下标计算的
																				
*/

//stack push pop top empty size
//
//Stack 将deque适配了
template<typename T,typename Container=deque<T>>
class Stack
{
public:
	void push(const T& val)
	{
		con.pushback(val);
	}
private:
	Container con;
};


int main()
{


	return 0;
}

无序关联容器

#include <iostream>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
using namespace std;

/*
	关联容器
	无序关联容器:链式哈希表,增删查O(1)
	set 集合 (key)
	map 映射表(key,value) 键值对

	unordered_set		单重集合			不允许key重复
	unordered_multiset	多重集合			允许key重复
	unordered_map		单重映射表
	unordered_multimap	多重映射表
*/

// 处理海量数据查重复,去重复

int main()
{
	//用整形实例化了一个单重的 无序的集合 set1
	unordered_set<int> set1;		//不会存储key值重复的元素
	for (int i = 0; i < 20; ++i)
	{
		//哈希表往哪里插入由哈希函数决定,和不需要像线性表那样给出迭代器位置
		set1.insert(rand() % 20 + 1);
	}

	//size 返回容器中的元素的个数
	//count 返回key为15的元素的个数
	//erase 按key值删除元素 连续删除就需要考虑迭代器失效问题,使用while删除的话迭代器不移动 增加一个迭代器,it自增两次
	//find 找20的key是不是存在 存在返回迭代器/不存在返回末尾迭代器
	unordered_set<int>::iterator it1 = set1.begin();
	for (; it1 != set1.end(); ++it1)
	{
		cout << *it1 << endl;
	}

	//map
	//存一个键值对,需要将两个打包成一个类型才能插入,class pair
	//提供了中括号重载函数 map operator[](key) 查询 副作用:如果key不存在,他会插入一对数据,(key,value)
	//erase(key)
	//find(key)查到了返回迭代器,查不到返回末尾迭代器 .end()
	//it1->first it1->second
	unordered_map<int, double> map1;
	map1.insert(make_pair(1000, 10.01));
	map1.insert({ 1001,10.02 });
	map1[200] = 12.06; //map1.insert({200,12.06})

	//需要常引用,只能遍历,不能修改
	for (pair<int, double> p : map1)
	{
		if (p.second > 1)
		{
			cout << "key" << endl;
		}
	}
	

	return 0;
}

有序关联容器

#include<iostream>

#include <set>
#include <map>
using namespace std;

// 使用底层数据结构 红黑树

class Student
{
public:
	Student(int id, string name)
		:_id(id), name(name)
	{

	}
	bool operator< (const Student stu)const
	{
		return _id < stu._id;
	}
private:
	int _id;
	string name;

};

//map erase(iterator),erase(key)都可以删除 
//注意 中括号重载需要默认值的构造函数,因为会插入默认构造对象
int main()
{
	//自定义类型使用有序容器需要提供小于运算符的重载
	set<int> set1;
	for (int i = 0; i < 20; ++i)
	{
		set1.insert(rand() % 20 + 1);
	}

	//中序遍历访问红黑树
	for (int v : set1)
	{
		cout << v << endl;
	}

}

迭代器

	容器的迭代器 
	普通正向迭代器		iterator 可以修改指向元素的值
	常量的正向迭代器	const_iterator 只能读而不能写
	反向迭代器		reverse_iterator	rbegin()最后一个元素反向迭代器表示 rend()返回首元素前驱位置的迭代器表示
	常量反向迭代器		const_reverse_iterator

函数对象

#include <iostream>
using namespace std;

/*
函数对象: C 中的函数指针
		把operator()小括号运算符重载函数的对象,称作函数对象或者仿函数
		实参可以推导模板类型

		1.通过函数对象调用小括号重载,可以省略函数调用开销,比通过函数指针调用函数效率高(可以内链)
		2.由于函数对象是用类生成的,所以可以添加想要的属性,成员变量,用来记录函数对象使用时更多的信息,对于类的封装和隐藏
		3.通过传入不同的函数对象,做不同的算法行为
*/
template<typename T>
bool greater(T a, T b)
{
	return a > b;
}
template<typename T>
bool less(T a, T b)
{
	return a < b;
}
//使用函数指针解决问题
template<typename T,typename Compare>
bool compare(T a, T b, Compare comp)
{
	//通过函数指针调用函数,是没有办法内联的,因为有函数调用开销,函数调用栈帧和回退
	//内敛发生在编译阶段,但是编译的时候不知道我到底调用的是什么

	//使用函数对象减少了函数开销,省略函数调用开销
	return comp(a, b);
}



class Sum
{
public:
	//二元函数对象
	int operator()(int a, int b)
	{
		return a + b;
	}
private:
};

//函数对象版本
template<typename T>
class mygreater
{
public:
	bool operator()(T a, T b)
	{
		return a > b;
	}
};
template<typename T>
class myless
{
public:
	bool operator()(T a, T b)
	{
		return a < b;
	}
};


int main()
{
	Sum sum;
	int ret = sum(10, 15);
	compare(10, 20, mygreater<int>());
	compare(10, 20, myless<int>());

	cout << ret << endl;
}

泛型算法

头文件 #include<algorithm>

sort/find/find_if/binary_serach/for_each
#include <iostream>
#include <vector>
#include <algorithm>
#include<functional>
using namespace std;

/*
	泛型算法(template + iterator + funcOOP)
	特点一:参数接收的都是迭代器
	特点二:参数还可以接受函数对象(C 函数指针)

	绑定器+二元函数对象 = 一元函数对象
	bind1st:把二元函数对象的第一个形参绑定起来
	bind2nd:把二元函数对象的第二个形参绑定起来
*/

int main()
{
	int arr[] = { 12,4,5,14,34,67,87,26,12,55,99 };
	//两个迭代器将容器内容转移
	vector<int> vec(arr, arr + sizeof(arr) / sizeof(arr[0]));

	sort(vec.begin(), vec.end());
	for (auto v: vec)
	{
		cout << v << endl;
	}

	//有序队列使用二分查找
	auto it1 = binary_search(vec.begin(), vec.end(), 21);

	//把48按序插入到vector中,找第一个小于48的元素
	auto it2 = find_if(vec.begin(), vec.end(), bind1st(greater<int>(), 48));
	vec.insert(it2, 48);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值