C++ STL 容器接口使用方法整理

stl 容器的基本知识(常识部分)


容器内元素的条件

(1)必须可以复制(copy)或者搬移(move) (隐含的条件是在拷贝和搬移的过程中应该没有副作用)    

struct BadStruct {
     BadStruct() : m_id(g_id++) {}
     //每次赋值或者搬移都会调用析构函数,因此析构函数中不应该做事
     ~BadStruct() { std::cout << "bye\n";}  
     int m_id;
     static int g_id;
};

(2) 元素必须可以被赋值操作来复制或者搬移 (因为容器和算法对复写的要求)
=
(3)元素可以被销毁

 

针对不同的容器还有特殊的要求

  • 对于序列式容器,元素必须有默认的构造函数,析构函数不能抛出异常
  • 对于某些操作,元素需要定义 == std::find
  • 对于关联式容器,排序准则默认的是 <(小于号)
  • 无顺序容器,必须要提供一个hash函数 ==
  • stl容器里面存的是元素的值而不是引用

 

容器通用接口

template <typename T>
void containerAllInterface(T& a, T& b) {
	T c;
	T d(a); // copy
	T e = a; // copy
	T f(std::move(a)); // move
	auto iterB = b.begin();
	auto iterE = b.end();
	T g(iterB, iterE); // copy
	b.size(); // std::forward_list 不支持size
	b.empty(); // return b.size() == 0;
	b.max_size();
	if(b == c) { // ==
	}
	if(b != d) { // !(b == d)
	}
	if(b < e) { // unordered_set unordered_map不支持这种比较
		// b <= e
		// b > e
		// b >= e
	}
	e = b;
	e = std::move(b);
	e.swap(g); // std::array 调用swap的时间复杂度是线性的,其余容器调用swap的时间复杂度是 O1
	swap(e,g); // 01 除了 std::array

	e.cbegin(); //返回值是const迭代器,即 const_iterator
	auto ea = e.cbegin();
	auto eea = e.begin();
	*eea; // -> ???? const &, &
	*ea; // -> const &

	e.cend();
	e.clear(); // std::array  不支持clear
}

 


array

 

array 实际上是对c/c++语言中原生数组进行的封装

特点:内存分配在栈(stack),绝对不会重新分配,随机访问元素

//由于我们是按引用传入的参数,因此该函数仅适用于单线程
//多线程情况下会出现数据混乱
template<typename C>
void checkSize(C& c) {
	if(c.size() > 3) {
		c[3] = 10;
	}
	//c.at(3) = 10;
}

void arrayPart() {
	// array 实际上是对c/c++语言中原生数组进行的封装
	// namespace std {
	// template<typename T, size_t N>
	// class array;
	// }
	// 特点:内存分配在栈(stack),绝对不会重新分配,随机访问元素
	int abc[100];                   //未初始化
	std::array<int, 100> a;         //未初始化
	std::array<int, 100> b = {};    //初始化了的
	// 以上两者的区别
	
	std::array<int, 5> obj = {1,2,3,4,5};
	std::array<int, 5> obj2 = {1,0};
	// 接口
	a.empty(); // nerver be true if size > 0
	a.size();
	a.max_size();
	// operator == < != > <= >=
	auto aa = a;

	aa.swap(a); //array是真的每一个元素都去做交换
	swap(aa, a);  //其他容器通过swap函数交换了指针

	// 访问元素
	a[1];
	a.at(1);
	a.front();
	a.back();
	checkSize(a);

	// 迭代器相关
	a.begin();
	a.end();
	a.cbegin();
	a.cend();
	a.rbegin();
	a.rend();
	a.crbegin();
	a.crend();

	// 和C的接口互用
	std::array<char, 100> carr;
	strcpy(&carr[0], "hello world\n"); // more better use carr.data();
	printf("%s", &carr[0]); // more better use carr.data()
	// 错误的用法,因为array的迭代器的实现有可能不是指针,因此下面的方式是错误的
	printf("%s", carr.begin());

	// 特殊的地方  获取特殊位置的值
	auto info = std::get<1>(carr);
	//对所有的元素进行赋值
	carr.fill(0);

	// 异常exception
	// c.at(pos);   调用at函数的时候有可能会抛出异常
	// copy move swap  拷贝、move和swap时,也可能会抛出异常
} 

 

 

 


vector

static void vectorPart() {
	// vector 是c++98中引入的动态数组(dynamic array)
	// namespace std {
	//	   template<typename T, typename Allocator = allocator<T>>
	//     class vector;
	// }
	// 特点随机访问元素,末端添加删除元素效率高。前端和中间删除和添加元素效率低,
	// 存在当前容器大小和容量的关系
	using Group = std::vector<float>;   //新式写法
	//typedef std::vector<float> Group;   //老式写法

	Group a;
	Group b = a;
	Group c(a);
	Group d(10);
	Group e(10, 1.0f);
	Group f(e.begin(), e.end());
	Group g({1.0f, 2.0f, 3.0f});
	Group h = {1.0f, 3.0f, 4.0f}; // initialize list
	
	d.empty();
	d.size();
	d.max_size();   //相对于其他容器来说,返回值会比较小
	d.capacity();
	d.reserve(100);  //预先的生成并保留这些空间
	d.shrink_to_fit(); // c++11  
	// operator == != < > <= >=
	
	// 赋值
	b = g;
	b.assign(3, 1.0f); // { 1.0f, 1.0f, 1.0f}
	b.assign(g.begin(), g.end()); //等价于: b = g
	b.assign({1.0f, 2.0f, 3.0f}); //
	
	// 交换
	b.swap(a); // swap十分高效且不会抛出异常
	std::swap(a,b);

	// 元素访问
	b[0];
	// at函数访问相应位置的元素,如果元素位置不合法,则会抛出异常 std::out_of_range
	b.at(0); 

	if(b.empty()) {
		b.front(); // undefined
		b.back(); // undefined
	}
	b.front();
	b.back();

	// 迭代器相关
	a.begin();
	a.end();
	a.cbegin();
	a.cend();
	a.rbegin();
	a.rend();
	a.crbegin();
	a.crend();

	// 当vector中没有元素的时候,会出现undefined行为
	a.pop_back(); 

	// single thread
	// multithread maybe wrong
	if(!a.empty()) a.pop_back();

	//erase删除掉特定位置的元素之后,后面的元素会依次往前移动
	//由于stl追求效率,因此对于传入的参数不会进行检查。因此这块的正确性需要我们来把控
	//erase返回我要删除的元素的下一个位置。如果vector后面没有元素了,则erase会返回一个end
	auto iterAfter=b.erase(b.begin()); 
	b.erase(b.begin(), b.end());

	b.push_back(10.0f);
	b.pop_back();

	//在特定位置插入新元素
	auto iter = b.insert(b.end(), 100.0f);
	//insert函数的返回值是插入新元素之后,新元素所在位置的迭代器
	iter = b.insert(b.end(), 10, -10.0f); 
	b.insert(b.end(), h.begin(), h.end());
	b.emplace(b.end(), 10.0f); // c++11,emplace是原位生成
	b.emplace_back(10.0f); // c++11 && move copy&&
	// b.size() == 100
	b.resize(10);  //将vector的尺寸设置成10
	// b.size() == 10
	b.resize(100, 1.0f);
	b.resize(100000);
	b.clear(); // 清空vector中的元素,并调用元素的析构函数。但是vector所占内存不会发生变化
	b.shink_to_fit(); // c++11  让vector中所占内存根据所含元素个数来进行调整


	// 和C的接口互用
	std::vector<char> carr(100, 0);
	strcpy(&carr[0], "hello world\n"); // more better use carr.data();
	printf("%s", &carr[0]); // more better use carr.data()
	// 错误的用法
	printf("%s", carr.begin());

	// 异常
	// (1) push_back发生异常的时候,vector本身不会发生变化
	// (2) 元素 move/copy 没有异常的话, insert、 emplace、 emplace_back、 push_back都不会出现任何问题
	// (3) pop_back肯定不会发生异常
	// (4) 元素 move/copy 没有异常的话,erase也不会抛出异常
	// (5) swap clear  也不会抛出异常
	
	// 特殊——不要将bool类型的值存入vector中
	// std::vector<bool> never use it
}

 

 


deque

static void dequePart() {
	// deque 是c++98中引入的动态数组(dynamic array)
	// namespace std {
	//     template<typename T, typename Allocator = allocator<T>>
	//     class deque;
	// }
	// 特点随机访问元素,末端和头部添加删除元素效率高。中间删除和添加元素效率低,
	// 元素的访问和迭代比vector要慢,迭代器不能是普通的指针
	using Group = std::deque<float>;

	Group a;
	Group b = a;
	Group c(a);
	Group d(10);
	Group e(10, 1.0f);
	Group f(e.begin(), e.end());
	Group g({1.0f, 2.0f, 3.0f});
	Group h = {1.0f, 3.0f, 4.0f};
	
	d.empty();
	d.size();
	d.max_size();

	// 和vector不同,deque不提供以下的函数
	//d.capacity();
	//d.reserve(100);
	d.shrink_to_fit();  //存在该函数
	// operator == != < > <= >=
	
	// 赋值
	b = g;
	b.assign(3, 1.0f);
	b.assign(g.begin(), g.end());
	b.assign({1.0f, 2.0f, 3.0f});
	
	// 交换
	b.swap(a);
	std::swap(a,b);

	// 元素访问
	b[0];
	b.at(0);  //有可能会抛出异常
	b.front();
	b.back();

	// 迭代器相关
	a.begin();
	a.end();
	a.cbegin();
	a.cend();
	a.rbegin();
	a.rend();
	a.crbegin();
	a.crend();

	a.pop_back(); // maybe wrong
	if(!a.empty()) a.pop_back();

	b.erase(b.begin());
	b.erase(b.begin(), b.end());

	b.push_back(10.0f);
	b.pop_back();
	b.push_front(1.2f);
	b.emplace_front(1.3f);
	b.pop_front();
	auto iter = b.insert(b.end(), 100.0f);
	iter = b.insert(b.end(), 10, -10.0f);
	b.insert(b.end(), h.begin(), h.end());
	b.emplace(b.end(), 10.0f);
	b.emplace_back(10.0f);
	b.resize(10);
	b.resize(100, 1.0f);
	b.clear(); // notice
	b.shink_to_fit();



	// 异常
	// (1) push_back push_front  不会抛出异常
	// (2) 元素 move/copy 没有异常的话, insert 、emplace、 emplace_back、 push_back、emplace_front也不会抛出异常
	// (3) pop_back、pop_front
	// (4) 元素 move/copy 没有异常的话,erase也不会抛出异常
	// (5) swap clear

}

 

 


list

static void listPart() {

	// list 是c++98中引入的双向串列(doubley linked list)
	// namespace std {
	//     template<typename T, typename Allocator = allocator<T>>
	//     class list;
	// }
	// 特点不支持随机访问元素,访问头部和尾部元素速度快
	// 任何位置插入删除元素都很快,常量时间内完成
	// 插入和删除不会造成迭代器失效
	// 对于异常支持的好,出现异常对于list而言,要不成功,要不什么影响没有
	using Group = std::list<float>;

	Group a;
	Group b = a;
	Group c(a);
	Group d(10);
	Group e(10, 1.0f);
	Group f(e.begin(), e.end());
	Group g({1.0f, 2.0f, 3.0f});
	Group h = {1.0f, 3.0f, 4.0f};
	
	d.empty();
	d.size();
	d.max_size();
	//和vector不同,list不提供以下的函数
	//d.capacity();
	//d.reserve(100);
	//d.shrink_to_fit();
	// operator == != < > <= >=
	
	// 赋值
	b = g;
	b.assign(3, 1.0f);
	b.assign(g.begin(), g.end());
	b.assign({1.0f, 2.0f, 3.0f});
	
	// 交换
	b.swap(a);
	std::swap(a,b);

	// 元素访问,不能随机访问
	//b[0];
	//b.at(0);
	b.front();
	b.back();

	// 迭代器相关
	a.begin();
	a.end();
	a.cbegin();
	a.cend();
	a.rbegin();
	a.rend();
	a.crbegin();
	a.crend();

	//下面代码是获取第五个元素的两种方法:
	//第一种方法,遍历到第五个元素
	auto iterBegin = a.begin();
	assert(a.size() >= 10);
	for(int i = 0;i < 5; ++i) ++iterBegin;
	//第二种方法,通过advance函数直接获取第五个元素
	std::advance(iterBegin, 4);
	//cpp 11 中使用next函数来获取第五个元素
	auto iter5 = std::next(iterBegin, 4);
	/*
	advance和next的区别:

	std::advance	
	    modifies its argument
	    returns nothing
	    works on input iterators or better (or bi-directional iterators if a negative distance is given)	

	std::next	
	    leaves its argument unmodified
	    returns a copy of the argument, advanced by the specified amount
	    works on forward iterators or better (or bi-directional iterators if a negative distance is given))
	*/


	a.pop_back(); // maybe wrong
	if(!a.empty()) a.pop_back();

	b.erase(b.begin());
	b.erase(b.begin(), b.end());

	b.push_back(10.0f);
	b.pop_back();
	b.push_front(1.2f);
	b.emplace_front(1.3f);
	auto iter = b.insert(b.end(), 100.0f);
	iter = b.insert(b.end(), 10, -10.0f);
	b.insert(b.end(), h.begin(), h.end());
	b.emplace(b.end(), 10.0f);
	b.emplace_back(10.0f);
	b.resize(10);
	b.resize(100, 1.0f);
	// 算法
	b.remove(1.0f);  //删除list中所有的1.0f
	b.remove_if([](auto v) { return v > 100.0f;});  //删除满足条件的所有元素
	b.reverse(); //反转链表   1 2 3 4 -> 4 3 2 1
	//std::sort(a.begin(), a.end());
	b.sort(); // list自己实现的sort算法,算法sort对于list不实用
	g.sort(); //
	b.merge(g); //排好序的两个list
	c.unique(); //排好序的两个list    1 1 2 2 1 1 3 4 -> 1 2 1 3 4
	c.splice(c.begin(), b); //将b作为一块安插到c的头部
}

 

 


forward_list

static void forwardListPart() {

	// forward_list 是c++11中引入的单向串列(singly linked list)
	// namespace std {
	//    template<typename T, typename Allocator = allocator<T>>
	//    class forward_list;
	// }
	// 特点不支持随机访问元素,访问头部元素速度快
	// "forward_list 和自己手写的c-style singly linked list相比,
	// 没有任何时间和空间上的额外开销。任何性质如果和这个目标抵触,我们放弃该特征。"
	// 任何位置插入删除元素都很快,常量时间内完成
	// 插入和删除不会造成迭代器失效
	// 对于异常支持的好,出现异常对于forward_list而言,要不成功,要不什么影响没有
	using Group = std::forward_list<float>;

	Group a;
	Group b = a;
	Group c(a);
	Group d(10);
	Group e(10, 1.0f);
	Group f(e.begin(), e.end());
	Group g({1.0f, 2.0f, 3.0f});
	Group h = {1.0f, 3.0f, 4.0f};
	
	d.empty();
	//d.size(); 不存在size函数
	d.max_size();
	// 和vector不同,forward_list不提供以下的函数
	//d.capacity();
	//d.reserve(100);
	//d.shrink_to_fit();
	// operator == != < > <= >=
	
	// 赋值
	b = g;
	b.assign(3, 1.0f);
	b.assign(g.begin(), g.end());
	b.assign({1.0f, 2.0f, 3.0f});
	
	// 交换
	b.swap(a);
	std::swap(a,b);

	// 元素访问,不能随机访问
	//b[0];
	//b.at(0);
	b.front();
	//b.back();  不能直接访问最后一个元素

	// 迭代器相关
	a.begin();
	a.end();
	a.cbegin();
	a.cend();
	//auto iter = a.before_begin();
	//*iter; // undefined
	a.before_begin();  //返回第一个有效位置的前一个位置
	c.cbefore_begin();  //返回第一个有效位置的前一个位置
//	a.rbegin();
//	a.rend();
//	a.crbegin();
//	a.crend();
	auto iterBegin = a.begin();


	//a.pop_back(); // maybe wrong
	//if(!a.empty()) a.pop_back();

	// list的erase函数会返回下一个元素的位置,forward_list的这些函数返回void
	b.erase_after(b.before_begin()); // return void  删除下一个位置的元素
	b.erase_after(b.before_begin(), b.end()); // return void

	//b.push_back(10.0f);   不支持push_back
	//b.pop_back();
	b.push_front(1.2f);
	b.emplace_front(1.3f);
	auto iter = b.insert_after(b.before_begin(), 100.0f); 
	iter = b.insert_after(b.before_begin(), 10, -10.0f);
	b.insert_after(b.before_begin(), h.begin(), h.end());
	//b.emplace(b.end(), 10.0f);
	//b.emplace_back(10.0f);
	b.resize(10);
	b.resize(100, 1.0f);
	// 算法
	b.remove(1.0f);
	b.remove_if([](auto v) { return v > 100.0f;});
	b.reverse(); // 1 2 3 4 -> 4 3 2 1
	//std::sort(a.begin(), a.end());
	b.sort(); // <
	g.sort(); //
	b.merge(g);
	c.unique(); // 1 1 2 2 1 1 3 4 -> 1 2 1 3 4
	c.splice_after(c.before_begin(), b);  //将b作为一块安插到c的头部

	//在第三个元素前插入一个元素的例子
	Group forlist = { 1, 2, 3, 4, 5};
	auto fiter = forlist.before_begin();
	for(int i = 0; i < 2; ++i) ++fiter;
	forlist.insert_after(fiter, 10);

}

 

 


set

static void setPart() {
	// set multiset 是c++98中引入的二叉树数据结构
	// namespace std {
	//     template<typename T, typename Compare = less<T>, typename Allocator = allocator<T>>
	//     class set;
	//     template<typename T, typename Compare = less<T>, typename Allocator = allocator<T>>
	//     class multiset;
	// }
	// 特点自动将元素排序
	// 插入、删除、查找的时间复杂度O(logn)

	// 插入的元素必须支持严格的弱顺序
	// (1) x < y == true, y < x == false
	// (2) x < y == true, y < z == true, x < z == true
	// (3) x < x === false
	// (4) a == b, b == c, c == a
	// 不能改变元素的值
	//
	// 辅助的类——pair
	// namespace std {
	//     template<typename T1, typename T2>
	//     struct pair {
	//         T1 first;
	//         T2 second;
	//     };
	// }
	using Group = std::set<float>;
	Group a;
	Group b = a;
	Group c(a);
	Group d(c.begin(), c.end());
	Group g({ 1.0f, 4.0f, 3.0f });
	// 1.0f
	// 1.0f 4.0f
	// 1.0f 3.0f 4.0f -> 1.0f 4.0f 3.0f
	Group h = { 1.0f, 3.0f, 4.0f };

	d.empty();
	d.size();
	d.max_size();
	// operator == != < > <= >=
	// special
	auto keycomp = c.key_comp();  //没用过
	auto valuecomp = c.value_comp();  //没用过

	// 赋值
	b = g;

	// 交换
	b.swap(a);
	std::swap(a, b);


	// 迭代器相关
	a.begin();
	a.end();
	a.cbegin();
	a.cend();
	a.rbegin();
	a.rend();
	a.crbegin();
	a.crend();
	auto iterBegin = a.begin();

	//算法函数
	//count的返回值0表示不存在这个值,1代表存在这个值
	// multiset中count函数的返回值是>= 0的,如果不存在,则返回0;如果存在,则会将出现的数量返回给你
	auto num = a.count(1.0f); 
	//find的返回值是迭代器
	auto findIter = a.find(1.0f);
	if (findIter == a.end()) {
		// not finded
	} else {
		*findIter;
	}
	//lower_bound——返回的位置的值大于等于你要插入的值
	auto lower = a.lower_bound(1.0f);
	if (lower != a.end()) {
		if (*lower == 1.0f) {
			// has 1.0f
		}
	}
	//返回的位置的值大于你要插入的值
	auto high = a.upper_bound(1.0f);
	//equal_range的返回值 std::make_pair(a.lower_bound(1.0f), a.upper_bound(1.0f));
	auto range = a.equal_range(1.0f); 

	auto eraseIter = b.erase(b.begin());
	eraseIter = b.erase(b.begin(), b.end());

	//insert的返回值是一个pair<Iterator, bool>
	auto state = b.insert(100.0f);
	auto insertIter = b.insert(c.begin(), c.end());
	b.emplace(10.0f);
	b.emplace_hint(b.end(), 100.0f);
}

 

TestSetBound——测试set的各种bound函数

注意:对于迭代器的返回值,一定要判断其是否有效。

#include <set>
#include <iostream>

int main() {
	using Group = std::set<int>;
	Group a = {1,4,2,5,6};
	for(auto& v : a) {
		std::cout << v << " ";  // 1 2 4 5 6
	}
	std::cout << std::endl;

	std::cout << "check to insert 3 for position:\n";
	auto lb = a.lower_bound(3);  
	auto ub = a.upper_bound(3);  
	auto er = a.equal_range(3);  

	std::cout << "lower bound for 3 " << *lb << std::endl;     //  4
	std::cout << "upper bound for 3 " << *ub << std::endl;     //  4
	std::cout << "equal range for 3 " << *(er.first) << " : "  //  4 :4
		<< *(er.second) << std::endl;

	std::cout << "check to insert 5 for position:\n";
	lb = a.lower_bound(5);
	ub = a.upper_bound(5);
	er = a.equal_range(5);

	std::cout << "lower bound for 5 " << *lb << std::endl; // 5
	std::cout << "upper bound for 5 " << *ub << std::endl; //6
	std::cout << "equal range for 5 " << *(er.first) << " : " // 5 : 6
		<< *(er.second) << std::endl;
}

  • lower_bound——返回的位置是大于等于你要插入的值
  • upper_bound——返回的位置是大于你要插入的值
  • equal_range——返回一个pair,第一个值是lower_boud的返回值,第二个值是upper_bound的返回值

 

 


map

static void mapPart() {

	// map multimap是c++98中引入的二叉树数据结构。key是const  key,因此无法修改
	// namespace std {
	// template<typename Key, typename T, typename Compare = less<Key>, typename Allocator = allocator<pair<const Key, T>>
	// class map;
	// template<typename Key, typename T, typename Compare = less<Key>, typename Allocator =locator<pair<const Key, T>>
	// class multimap;
	// }
	// 特点自动将元素排序
	// 插入和删除查找O(logn)
	// 必须Key元素必须支持严格的弱顺序
	// (1) x < y == true, y < x == false
	// (2) x < y == true, y < z == true, x < z == true
	// (3) x < x === false
	// (4) a == b, b == c, c == a
	// 不能改变Key元素的值
	using Group = std::map<int, std::string>;
	Group a;
	Group b = a;
	Group c(a);
	Group d(c.begin(), c.end());
	Group g({ {1, "a"}, {2,"test"}, {3, "test"} });

	d.empty();
	d.size();
	d.max_size();
	// operator == != < > <= >=
	// special
	auto keycomp = c.key_comp();
	auto valuecomp = c.value_comp();

	// 赋值
	b = g;

	// 交换
	b.swap(a);
	std::swap(a, b);


	// 迭代器相关
	a.begin();
	a.end();
	a.cbegin();
	a.cend();
	a.rbegin();
	a.rend();
	a.crbegin();
	a.crend();
	auto iterBegin = a.begin();

	//算法函数
	// map count 0 1
	// multimap count >= 0
	auto num = a.count(1);
	auto findIter = a.find(1);
	if (findIter == a.end()) {
		// not finded
	}
	else {
		//*findIter; // 解引用之后得到的std::pair<const int, std::string>&
		//注意key是const int类型,因此无法修改
	}
	auto lower = a.lower_bound(1);
	if (lower != a.end()) {
		if (*lower.first == 1) {
			// has 1
		}
	}
	auto high = a.upper_bound(1);
	auto range = a.equal_range(1); // return std::make_pair(a.lower_bound(1), a.upper_bound(1));

	auto eraseIter = b.erase(b.begin());
	eraseIter = b.erase(b.begin(), b.end());

	// insert返回值是一个pair,第一个元素指向插入的迭代器的位置,第二个参数表示是否插入成功
	//state is a pair<Iterator, bool>
	auto state = b.insert(std::make_pair(100, "good")); 
	auto insertIter = b.insert(c.begin(), c.end());
	//emplace是按原位插入。由于cpp11引入了move才有的这些操作
	b.emplace(std::make_pair(10, "has it"));
	// 这句和下面那句等价—b.emplace( std::pair<const int,std::string>(11, std::string("again"));
	b.emplace(11, std::string("again")); 
	//这句和下面那句等价—b.emplace(std::pair<const int, std::string>(12, "third"));
	b.emplace(12, "third"); 
	b.emplace_hint(b.end(), 13, "haha");

	// map重载了[]。如果搜索的键值对不存在,则会创建一个这样的键值对,插入map中
	//插入过程为auto iter = b.insert(std::make_pair(13, std::string())).first; return (*iter).second;
	// auto这里的类型是string
	auto& info = b[10];

	// at  使用at查找,找到的情况下返回一个引用,没有的情况下返回一个异常
	//因此使用的时候需要用一个try catch将语句包起来。
	//这样的其实不如下面的更推荐的方式
	try {
		auto& findInfo = b.at(10); // 既可以是const,也可以是非const		                          
	}
	catch (...) {}

	//更推荐使用这种方式来进行查找
	auto findIter = b.find(10);
	if (findIter != std::end(b) /* b.end() */) {
		auto& v = (*findIter).second;
	}
	else {}

	//调用下面自己写的辅助函数来进行键值对查找
	auto info = get_default(b, 10);
	if (info.empty()) {}
	else {}
}

//写一个辅助函数,帮助我们查找键值对
template <class Map>
typename Map::mapped_type get_default(
	const Map &map, const typename Map::key_type &key,
	const typename Map::mapped_type &dflt = typename Map::mapped_type()) {
	auto pos = map.find(key);
	return (pos != map.end() ? pos->second : dflt);
}

 

 

 


unordered_set和unordered_map

static void unorderedSetAndMapPart() {

	// unordered_multiset unordered_set
	// unordered_map unordered_multimap是c++11中以hash table为基础的,内部元素没有明确的顺序的容器
	//namespace std {
	//	template<typename Key, typename T, typename Hash = hash<Key>, typename
	//		EqPred = equal_to<Key>, typename Allocator =
	//		allocator<pair<const Key, T>>
	//		class unorderd_map;
	//	template<typename Key, typename T, typename Hash = hash<Key>, typename
	//		EqPred = equal_to<T>, typename Allocator =
	//		allocator<pair<const Key, T>>
	//		class multimap;
	//	template<typename T, typename Hash = hash<T>, typename
	//		EqPred = equal_to<T>, typename Allocator =
	//		allocator<T>>
	//		class unorderd_set;
	//	template<typename T, typename Hash = hash<T>, typename
	//		EqPred = equal_to<T>, typename Allocator =
	//		allocator<T>>
	//		class unorderd_multiset;
	//}
	// 插入和删除查找O(1)
	// 不能改变Key元素的值
	using Group = std::unordered_map<int, std::string>;
	Group a;
	Group b = a;
	Group c(a);
	Group d(c.begin(), c.end());
	Group g({ {1, "a"}, {2,"test"}, {3, "test"} });

	d.empty();
	d.size();
	d.max_size();
	// operator == !=
	//  special
	// 赋值
	b = g;
	// 交换
	b.swap(a);
	std::swap(a, b);


	// 迭代器相关
	a.begin();
	a.end();
	a.cbegin();
	a.cend();
	a.rbegin();
	a.rend();
	a.crbegin();
	a.crend();
	auto iterBegin = a.begin();

	//算法函数
	// map count 0 1
	// multimap count >= 0
	auto num = a.count(1);
	auto findIter = a.find(1);
	if (findIter == a.end()) {
		// not finded
	}
	else {
		const std::pair<int, std::string>& obj = *findIter;
		//*findIter; // std::pair<const int, std::string>&
	}
	auto lower = a.lower_bound(1);
	if (lower != a.end()) {
		if (*lower.first == 1) {
			// has 1
		}
	}
	auto high = a.upper_bound(1);
	auto range = a.equal_range(1); // return std::make_pair(a.lower_bound(1), a.upper_bound(1));

	auto eraseIter = b.erase(b.begin());
	eraseIter = b.erase(b.begin(), b.end());

	auto state = b.insert(std::make_pair(100, "good")); // state is a pair<Iterator, bool>
	auto insertIter = b.insert(c.begin(), c.end());
	b.emplace(std::make_pair(10, "has it"));
    // b.emplace( std::pair<const int,std::string>(10, std::string("again"));
	b.emplace(11, std::string("again")); 
	b.emplace(12, "third"); // b.emplace(std::pair<const int, std::string>(10, "third"));
	b.emplace_hint(b.end(), 13, "haha");

	// 重载[]
	// auto string
	auto& info = b[10];
	//如果没找到,则执行[]之后的操作等价于:
    //auto iter = b.insert(std::make_pair(13, std::string())).first; return (*iter).second;

	// at
	try {
		auto& findInfo = b.at(10); // const
	}
	catch (...) {}
	auto findIter = b.find(10);
	if (findIter != std::end(b) /* b.end() */) {
		auto& v = (*findIter).second;
	}
	else {}

	auto info = get_default(b, 10);
	if (info.empty()) {}
	else {}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值