C++核心编程Day08

1.STL基本概念

1.1简介
	STL(Standard Template Library,标准模板库),STL 从广义上分为: 容器(container) 
算法(algorithm) 迭代器(iterator),容器和算法之间通过迭代器进行无缝连接。STL 几乎
所有的代码都采用了模板类或者模板函数,这相比传统的由函数和类组成的库来说提
供了更好的代码重用机会。

STL六大组件简介:
	容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据
	算法:各种常用的算法,如sort、find、copy、for_each。
	迭代器:扮演了容器与算法之间的胶合剂,共有五种类型
	仿函数:行为类似函数,可作为算法的某种策略。
	适配器:一种用来修饰容器或者仿函数或迭代器接口的东西。
	空间配置器:负责空间的配置与管理。配置器是实现了动态空间配置、空间管理、空间释放。

1.2 STL三大组件
	1.容器:分为序列式容器和关联式容器两种。
	2.算法:分为质变算法和非质变算法。
	3.迭代器:分为以下五类:
	输入迭代器		提供对数据的只读访问					只读,支持++、==、!=
	输出迭代器		提供对数据的只写访问					只写,支持++
	前向迭代器		提供读写操作,并能向前推进迭代器		读写,支持++、==、!=
	双向迭代器		提供读写操作,并能向前和向后操作		读写,支持++、--,
	随机访问迭代器	提供读写操作,并能在数据中随机移动		读写,支持++、--、[n]、-n、<、<=、>、>=

1.3 STL工作原理
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

//数组容器
template<class T>
class MyArr
{
public:
	//保护原生指针,给原生指针取别名
	typedef T* iterantor;
public:
	MyArr()
	{
		m_capacity = 10;
		m_size = 0;
		p = new T[m_capacity];
		for (int i = 0; i < m_capacity; i++)
		{
			p[i] = i + 1;
			m_size++;
		}
	}

	//提供迭代器,开始位置
	T* begin()
	{
		return p;
	}
	//提供迭代器,结束位置
	T* end()
	{
		return p+m_size;
	}

public:
	T* p;
	int m_capacity;
	int m_size;
};

template<class T>
void printArr(T begin,T end)
{
	for (;begin != end; ++begin)
	{
		cout << *begin << " ";
	}
}

void test01()
{
	MyArr<int> arr;

	//获取容器提供的迭代器
	MyArr<int>::iterantor begina = arr.begin();
	MyArr<int>::iterantor endd = arr.end();
	printArr(begina,endd);
}

int main()
{
	test01();
	system("pause");
	return 0;
}
1.4 STL的基本使用
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

//加入算法的回调函数
void MyPrint(int val)
{
	cout << val << " ";
}

void test01()
{
	vector<int> v;
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);
	v.push_back(50);

	//获取迭代器
	vector<int>::iterator begin = v.begin();
	vector<int>::iterator end = v.end();

	//遍历
	for_each(begin, end, MyPrint);

}

class Test
{
public:
	Test(string name,int age)
	{
		this->name = name;
		this->age = age;
	}

	string name;
	int age;
};

ostream& operator<<(ostream& cout, Test& t1)
{
	cout << "姓名:" << t1.name << " 年龄:" << t1.age << endl;
	return cout;
}

void test02()
{
	vector<Test> v;
	v.push_back(Test("张1", 18));
	v.push_back(Test("张2", 17));
	v.push_back(Test("张3", 19));
	v.push_back(Test("张4", 21));
	v.push_back(Test("张5", 20));

	//获取开始和结束位置迭代器
		
	vector<Test>::iterator begin = v.begin();
	vector<Test>::iterator end = v.end();

	while (begin != end)
	{
		cout << *(begin);
		++begin;
	}
}
//3.存放对象的指针
void test03()
{
	vector<Test* > v;

	Test* t1 = new Test("张1", 18);
	Test* t2 = new Test("张2", 17);
	Test* t3 = new Test("张3", 19);
	Test* t4 = new Test("张4", 21);
	Test* t5 = new Test("张5", 20);

	v.push_back(t1);
	v.push_back(t2);
	v.push_back(t3);
	v.push_back(t4);
	v.push_back(t5);

	vector<Test* >::iterator begin = v.begin();
	vector<Test* >::iterator end = v.end();

	while (begin != end)
	{
		cout << (*begin)->name<<" "<<(*begin)->age<<endl;
		++begin;
	}

	delete t1;
	delete t2;
	delete t3;
	delete t4;
	delete t5;

}

//4.容器嵌套容器
void test04()
{
	vector<vector<int>> v;

	vector<int> v1;
	vector<int> v2;
	vector<int> v3;
	vector<int> v4;
	vector<int> v5;

	for (int i = 0; i < 5; i++)
	{
		v1.push_back(i + 10);
		v2.push_back(i + 10);
		v3.push_back(i + 10);
		v4.push_back(i + 10);
		v5.push_back(i + 10);
	}

	v.push_back(v1);
	v.push_back(v2);
	v.push_back(v3);
	v.push_back(v4);
	v.push_back(v5);

	vector<vector<int>>::iterator begin = v.begin();
	vector<vector<int>>::iterator end = v.end();

	while (begin != end)
	{
		vector<int>::iterator s_begin = (*begin).begin();
		vector<int>::iterator s_end = (*begin).end();

		while (s_begin != s_end)
		{
			cout << (*s_begin) <<" ";
			++s_begin;
		}
		cout << endl; 
		++begin;
	}
}

int main()
{
	//test01();
	//test02();
	//test03();
	test04();

	system("pause");
	return 0;
}

2.容器

2.1 string容器
2.1.1 string容器基本概念
	C风格字符串(以空字符结尾的字符数组)太过复杂难于掌握,不适合大程序的开发,
所以C++标准库定义了一种string类,定义在头文件<string>。
	String和c风格字符串对比:
	1.Char*是一个指针,String是一个类
	  string封装了char*,管理这个字符串,是一个char*型的容器。
	2.String封装了很多实用的成员方法
	  查找find,拷贝copy,删除delete 替换replace,插入insert
	3.不用考虑内存释放和越界
	  string管理char*所分配的内存。每一次string的复制,取值都由string类负责维护,
	  不用担心复制越界和取值越界等。
2.1.2 string容器的常用操作
		1 string 构造函数
			string();//创建一个空的字符串 例如: string str;      
			string(conststring& str);//使用一个string对象初始化另一个string对象
			string(constchar* s);//使用字符串s初始化
			string(int n, char c);//使用n个字符c初始化 
			
		2 string基本赋值操作
			string&operator=(constchar* s);//char*类型字符串 赋值给当前的字符串
			string&operator=(conststring&s);//把字符串s赋给当前的字符串
			string&operator=(char c);//字符赋值给当前的字符串
			string& assign(constchar *s);//把字符串s赋给当前的字符串
			string& assign(constchar *s, int n);//把字符串s的前n个字符赋给当前的字符串
			string& assign(conststring&s);//把字符串s赋给当前字符串
			string& assign(int n, char c);//用n个字符c赋给当前字符串
			string& assign(conststring&s, int start, int n);//将s从start开始n个字符赋值给字符串,如s=hello,那么n=3,start=1,那么是hel中从e开始赋值3-1个字符

		3 string存取字符操作
			char&operator[](int n);//通过[]方式取字符
			char& at(int n);//通过at方法获取字符
			
		4 string拼接操作
			string&operator+=(conststring& str);//重载+=操作符
			string&operator+=(constchar* str);//重载+=操作符
			string&operator+=(constchar c);//重载+=操作符
			string& append(constchar *s);//把字符串s连接到当前字符串结尾
			string& append(constchar *s, int n);//把字符串s的前n个字符连接到当前字符串结尾
			string& append(conststring&s);//同operator+=()
			string& append(conststring&s, int pos, int n);//把字符串s中从pos开始的n个字符连接到当前字符串结尾
			string& append(int n, char c);//在当前字符串结尾添加n个字符c
			
		5 string查找和替换
			int find(conststring& str, int pos = 0) const; //查找str第一次出现位置,从pos开始查找
			int find(constchar* s, int pos = 0) const;  //查找s第一次出现位置,从pos开始查找
			int find(constchar* s, int pos, int n) const;  //从pos位置查找s的前n个字符第一次位置
			int find(constchar c, int pos = 0) const;  //查找字符c第一次出现位置
			int rfind(conststring& str, int pos = npos) const;//查找str最后一次位置,从pos开始查找
			int rfind(constchar* s, int pos = npos) const;//查找s最后一次出现位置,从pos开始查找
			int rfind(constchar* s, int pos, int n) const;//从pos查找s的前n个字符最后一次位置
			int rfind(constchar c, int pos = 0) const; //查找字符c最后一次出现位置
			string& replace(int pos, int n, conststring& str); //替换从pos开始n个字符为字符串str
			string& replace(int pos, int n, constchar* s); //替换从pos开始的n个字符为字符串s
	
		6 string比较操作
			/*
			compare函数在>时返回 1,<时返回 -1,==时返回 0。
			比较区分大小写,比较时参考字典顺序,排越前面的越小。
			大写的A比小写的a小。
			*/
			int compare(conststring&s) const;//与字符串s比较
			int compare(constchar *s) const;//与字符串s比较

		7 string子串
				string substr(int pos = 0, int n = npos) const;//返回由pos开始的n个字符组成的字符串
				
		8 string插入和删除操作
			string& insert(int pos, constchar* s); //插入字符串
			string& insert(int pos, conststring& str); //插入字符串
			string& insert(int pos, int n, char c);//在指定位置插入n个字符c
			string& erase(int pos, int n = npos);//删除从Pos开始的n个字符 

		9 string和c-style字符串转换
			//string 转 char*
			string str = "itcast";
			constchar* cstr = str.c_str();
			//char* 转 string 
			char* s = "itcast";
			string sstr(s);
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

//注意事项:
//			1.[]和at的区别,在于是抛出异常还是直接down掉,即[]会直接down掉,而at会抛出异常


//迭代器
void test()
{
	string::iterator it;
	it++;
	it--;
}
//1.初始化操作
void test01()
{
	string s1;
	string s2(10, 'a');//10个a
	string s3(s2);
	string s4("helloworld");
}
//2.赋值操作
void test02()
{
	string s1;
	s1 = "hello world";
	cout << s1 << endl;

	string s2;
	s2.assign(s1);
	s2.assign("world");
	cout << s2 << endl;
}

//3.存取字符操作
void test03()
{
	//[]和at的区别,[]访问元素的时候,如果越界不抛异常,直接挂掉
	//at越界会抛出异常
	string s = "hello world";
	for (int i = 0; i < s.size(); i++)
	{
		cout << s[i] << " ";
	}
	cout << endl;

	for (int i = 0; i < s.size(); i++)
	{
		cout << s.at(i) << " ";
	}
	cout << endl;
}
//4.拼接操作
void test04()
{
	string s1 = "aaa";
	s1 += "bbb";
	s1 += 'c';
	cout << s1 << endl;

	s1.append("ddddd", 3);
	cout << s1 << endl;
}
//5.查找和替换
void test05()
{
	string s = "abcdefgh";
	cout << s.find('d') << endl;
	//反序查找
	cout << s.rfind('d') << endl;

	cout << s.find('x') << endl;

	//替换
	//s.replace(2, 4, "AAAA");
	//cout << s << endl;
	//s.replace(2, 4, "AAA");
	//cout << s << endl;
	s.replace(2, 4, "AAAAAAAAAAAAAAAAAAAAAAA");
	cout << s << endl;
}
//6.比较
void test06()
{
	string s1 = "hello";
	string s2 = "hello";
	const char* chr = "world";

	if (s1.compare(s2) == 0)
		cout << "s1==s2" << endl;
	else
		cout << "s1!=s2" << endl;


	if (s2.compare(chr) == 0)
		cout << "s2 == chr" << endl;
	else
		cout << "s2 != chr" << endl;
}
//7.string字串
void test07()
{
	string email = "helloworld@qq.com";
	int pos = email.find('@');
	string user = email.substr(0, pos);
	cout << user << endl;

	int pos1 = email.find('.');
	string last_Name = email.substr(pos + 1, pos1-pos-1);
	cout << last_Name << endl;
}
//8.插入和删除操作
void test08()
{
	string s = "aaa";
	s.insert(2, "AAAAAAAA");
	cout << s << endl;

	s.insert(3, 5, 'B');
	cout << s << endl;

	s.erase(2, 3);
	cout << s << endl;
}

//9.string和C之间char的转换
void test09()
{
	const char* str = "hello";
	string s = string(str);
	cout << s << endl;

	const char* str1 = s.c_str();
	cout << str1 << endl;
}

//10.字符串内存重新分配,[]和at获取的字符引用可能会出错
void test10()
{
	string s = "abcde";

	char& a = s[2];
	char& b = s[3];

	a = '1';
	b = '2';
	cout << "a:" << a << endl;
	cout << "b:" << b << endl;
	cout << s << endl;

	cout << "字符串的原空间地址:" << (int*)s.c_str() << endl;
	s = "dasfhjkboivnwiornjgbbgjflkg cmxm nlvkdfj";
	cout << "字符串的空间地址:" << (int*)s.c_str() << endl;
	//空间改变后,再使用a,b的话会使得空间down掉,因为之前操作的那片空间已经被释放,现在是一片新的空间
	//a = 'c';//error
	//b = 'd';//error
}
//11迭代器遍历
void test11()
{
	string s = "helloworld";
	for (string::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
	//反向遍历
	for (string::reverse_iterator it = s.rbegin(); it != s.rend(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

int main()
{
	//test01();
	//test02();
	//test03();
	//test04();
	//test05();
	//test06();
	//test07();
	//test08();
	//test09();
	//test10();
	test11();


	system("pause");
	return 0;
}
2.2 vector容器
	2.2.1 vector容器基本概念
	vector的数据安排以及操作方式,与array非常相似,两者的唯一差别在于空间的
运用的灵活性。Array是静态空间,一旦配置了就不能改变,要换大一点或者小一点
的空间,可以,一切琐碎得由自己来,首先配置一块新的空间,然后将旧空间的数
据搬往新空间,再释放原来的空间。Vector是动态空间,随着元素的加入,它的内
部机制会自动扩充空间以容纳新元素

	2.2.2 vector的数据结构
	Vector所采用的数据结构非常简单,线性连续空间,它以两个迭代器_Myfirst和_Mylast
分别指向配置得来的连续空间中目前已被使用的范围,并以迭代器_Myend指向整块连续
内存空间的尾端。
	为了降低空间配置时的速度成本,vector实际配置的大小可能比客户端需求大一些,以
备将来可能的扩充,这边是容量的概念
		
	2.2.3 vector常用接口
	1 vector构造函数
	vector<T> v; //采用模板实现类实现,默认构造函数
	vector(v.begin(), v.end());//将v[begin(), end())区间中的元素拷贝给本身。
	vector(n, elem);//构造函数将n个elem拷贝给本身。
	vector(const vector &vec);//拷贝构造函数。

	2 vector常用赋值操作
	assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
	assign(n, elem);//将n个elem拷贝赋值给本身。
	vector&operator=(const vector  &vec);//重载等号操作符
	swap(vec);// 将vec与本身的元素互换。

	3 vector大小操作
	size();//返回容器中元素的个数
	empty();//判断容器是否为空
	resize(int num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
	resize(int num, elem);//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。如果容器变短,则末尾超出容器长>度的元素被删除。
	capacity();//容器的容量
	reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问。

	4 vector数据存取操作
	at(int idx); //返回索引idx所指的数据,如果idx越界,抛出out_of_range异常。
	operator[];//返回索引idx所指的数据,越界时,运行直接报错
	front();//返回容器中第一个数据元素
	back();//返回容器中最后一个数据元素

	5 vector插入和删除操作
	insert(const_iterator pos, int count,ele);//迭代器指向位置pos插入count个元素ele.
	push_back(ele); //尾部插入元素ele
	pop_back();//删除最后一个元素
	erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素
	erase(const_iterator pos);//删除迭代器指向的元素
	clear();//删除容器中所有元素
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<vector>
using namespace std;

//注意事项:1.resize开辟空间并初始化,reserve开辟空间但是不初始化,没有初始化的空间不可以访问
//			2.reverse作用:如果容器要存储大量数据时,要先开辟空间,避免多次开辟
//			3.swap作用:可以缩小容器容量

void myPrintf(const vector<int> &v)
{
	for (vector<int>::const_iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";  
	}
	cout << endl;
	//for (vector<int>::reverse_iterator it = v.rbegin(); it != v.rend(); it++)
	//{
	//	cout << *it << endl;
	//}
}
//反向打印
void myReversePrintf(vector<int>& v)
{

	for (vector<int>::reverse_iterator it = v.rbegin(); it != v.rend(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

//1.构造函数
void test01()
{
	int arr[] = { 2,3,1,9,8 };
	vector<int> v(arr, (arr + sizeof(arr)/sizeof(int)));
	myPrintf(v);
	myReversePrintf(v);

	vector<int>v1(10, 6);
	myPrintf(v1);

}

//2.赋值操作
void test02()
{
	vector<int> v;
	v.assign(6, 10);

	vector<int> v2;
	v2.push_back(1);
	v2.push_back(2);
	v2.push_back(3);

	myPrintf(v);
	myPrintf(v2);

	cout << "-------------" << endl;
	//swap可以用来缩小容量
	v.swap(v2);
	myPrintf(v);
	myPrintf(v2);

}

//3.大小操作
void test03()
{
	//1.resize 开辟空间,并初始化
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);

	cout << "Size:" << v.size() << endl;
	cout << "Empty:" << v.empty() << endl;

	v.resize(5);
	cout << "Size:" << v.size() << endl;
	myPrintf(v);

	v.resize(20,11);
	v.push_back(20);
	myPrintf(v);
}
	//2.reserve 开辟空间,但不初始化
void test04()
{
	vector<int> v;
	v.reserve(10001000);

	int* p = NULL;
	int num = 0;

	for (int i = 0; i < 10001000; i++)
	{
		v.push_back(i);
		if (p != &v[0])
		{
			p = &v[0];
			++num;
		}
	}
	cout << "num = " << num << endl;
}

//4.数据存取操作
void test05()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);

	cout << v.front() << endl;
	cout << v.back() << endl;

	v.front() = 100;
	v.back() = 300;

	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << endl;
	}	
}

//5.插入和删除操作
void test06()
{
	vector<int> v;
	for (int i = 0; i < 5; i++)
	{
		v.push_back(i);
	}

	myPrintf(v);

	v.insert(v.begin() + 1,2, 100);
	myPrintf(v);

	v.pop_back();
	myPrintf(v);

	v.erase(v.begin());
	myPrintf(v);

	v.erase(v.begin()+1,v.end()-1);
	myPrintf(v);

	v.clear();
	myPrintf(v);

}

int main()
{
	//test01();
	//test02();
	//test03();
	//test04();
	//test05();
	test06();

	system("pause");
	return 0;
}
2.3  deque容器
	2.3.1 deque容器基本概念
	Vector容器是单向开口的连续内存空间,deque则是一种双向开口的连续线性空间。
所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作

	2.3.2 deque容器实现原理
	Deque容器是连续的空间,至少逻辑上看来如此,连续现行空间总是令我们联想到
array和vector,array无法成长,vector虽可成长,却只能向尾端成长,而且其成长其实
是一个假象,事实上(1) 申请更大空间 (2)原数据复制新空间 (3)释放原空间 三步骤,
如果不是vector每次配置新的空间时都留有余裕,其成长假象所带来的代价是非常昂
贵的。
	Deque是由一段一段的定量的连续空间构成。一旦有必要在deque前端或者尾端增加
新的空间,便配置一段连续定量的空间,串接在deque的头端或者尾端。Deque最大的工
作就是维护这些分段连续的内存空间的整体性的假象,并提供随机存取的接口,避开了
重新配置空间,复制,释放的轮回,代价就是复杂的迭代器架构。
	既然deque是分段连续内存空间,那么就必须有中央控制,维持整体连续的假象,数
据结构的设计及迭代器的前进后退操作颇为繁琐。Deque代码的实现远比vector或list都
多得多。
	Deque采取一块所谓的map(注意,不是STL的map容器)作为主控,这里所谓的map是
一小块连续的内存空间,其中每一个元素(此处成为一个结点)都是一个指针,指向另一段
连续性内存空间,称作缓冲区。缓冲区才是deque的存储空间的主体。

2.3.2 deque常用API
	1 deque构造函数
	deque<T> deqT;//默认构造形式
	deque(beg, end);//构造函数将[beg, end)区间中的元素拷贝给本身。
	deque(n, elem);//构造函数将n个elem拷贝给本身。
	deque(const deque &deq);//拷贝构造函数。

	2 deque赋值操作
	assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
	assign(n, elem);//将n个elem拷贝赋值给本身。
	deque&operator=(const deque &deq); //重载等号操作符 
	swap(deq);// 将deq与本身的元素互换

	3 deque大小操作
	deque.size();//返回容器中元素的个数
	deque.empty();//判断容器是否为空
	deque.resize(num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
	deque.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除。

	4 deque双端插入和删除操作
	push_back(elem);//在容器尾部添加一个数据
	push_front(elem);//在容器头部插入一个数据
	pop_back();//删除容器最后一个数据
	pop_front();//删除容器第一个数据

	5 deque双端插入和删除操作
	at(idx);//返回索引idx所指的数据,如果idx越界,抛出out_of_range。
	operator[];//返回索引idx所指的数据,如果idx越界,不抛出异常,直接出错。
	front();//返回第一个数据。
	back();//返回最后一个数据
	
	6 deque插入操作
	insert(pos,elem);//在pos位置插入一个elem元素的拷贝,返回新数据的位置。
	insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
	insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。
			
	7 deque删除操作
	clear();//移除容器的所有数据
	erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
	erase(pos);//删除pos位置的数据,返回下一个数据的位置。
#define _CRT_SECURE_NO_WARNINGS
#include<deque>
#include<string>
#include<iostream>
using namespace std;

void myPrintf(const deque<int>& v)
{
	for (deque<int>::const_iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test()
{
	deque<int>::iterator it;
	it++;
	it--;
}
//1.构造函数
void test01()
{
	int arr[] = { 2,3,1,9,8 };
	deque<int> d(arr, (arr + sizeof(arr) / sizeof(int)));
	myPrintf(d);

	deque<int> d1(10, 6);
	myPrintf(d1);

	deque<int> d2(d);
	myPrintf(d2);
}

//2.赋值操作
void test02()
{
	int arr[] = { 2,3,1,9,8 };
	deque<int> d(arr, (arr + sizeof(arr) / sizeof(int)));
	myPrintf(d);

	deque<int> d2;
	d2.assign(d.begin(), d.end());
	d2.push_back(100);
	myPrintf(d2);

	d.swap(d2);
	myPrintf(d);
	myPrintf(d2);
}

//3.大小操作
void test03()
{
	deque<int> d;
	cout << d.size() << endl;

	if (d.empty() == true)
		cout << "空!" << endl;
	else
		cout << "非空!" << endl;

	d.resize(10, 7);
	myPrintf(d);
}
//4.双端插入和删除
void test04()
{
	deque<int> d;
	d.push_back(1);
	d.push_back(2);
	d.push_back(3);
	d.push_front(666);
	myPrintf(d);

	d[0] = 200;
	myPrintf(d);

	//d.at(8) = 800;//越界,抛出异常
	d.at(1) = 800;
	myPrintf(d);

	d.pop_back();
	d.pop_front();
	myPrintf(d);
}

//5.插入和删除
void test05()
{
	deque<int> d;
	d.push_back(10);
	d.push_back(20);
	d.push_back(30);
	d.push_back(40);
	d.push_back(50);
	myPrintf(d);

	d.insert(d.begin() + 1, 1000);
	myPrintf(d);

	d.insert(d.begin() + 1,2, 2000);
	myPrintf(d);

	deque<int> d1;
	d1.push_back(1);
	d1.push_back(2);
	d1.push_back(3);

	d.insert(d.begin(), d1.begin(), d1.end());
	myPrintf(d);
	cout << "---------------" << endl;

	deque<int> d2;
	d2.push_back(10);
	d2.push_back(20);
	d2.push_back(30);
	d2.push_back(40);
	d2.push_back(50);

	deque<int>::iterator it = d2.erase(d2.begin() + 1, d2.end() - 1);
	myPrintf(d2);
	cout << *it << endl;
	d2.clear();
	myPrintf(d2);

}

int main()
{
	//test01();
	//test02();
	//test03();
	//test04();
	test05();

	system("pause");
	return 0;
}
2.4 案例
	十个评委分别给5名学生打分,去掉最高分再去掉最低分求和后取平均,就是这名学
生的最终成绩。
#define _CRT_SECURE_NO_WARNINGS
#include<deque>
#include<string>
#include<vector>
#include<iostream>
#include<algorithm>
#include<time.h>
using namespace std;

class Student
{
public:
	Student(){}
	Student(int score,string name)
	{
		this->score = score;
		this->name = name;
	}
	int myScore()
	{
		return this->score;
	}

	string name;
	int score;
};

void creatStu(vector<Student>& v)
{
	string id_Str = "ABCDE";
	for (int i = 0; i < 5; i++)
	{
		Student s;
		s.score = 0;
		s.name = "学生";
		s.name += id_Str[i];
		v.push_back(s);
	}
}

void putScore(vector<Student> &v)
{
	for (vector<Student>::iterator it = v.begin(); it != v.end(); it++)
	{
		deque<int> d;
		for (int i = 0; i < 10; i++)
		{
			int score = rand() % 70 + 30;
			d.push_back(score);
		}
		//排序后删除最低和最高分
		sort(d.begin(), d.end());
		d.pop_back();
		d.pop_front();

		int sum = 0;
		for (deque<int>::iterator dit = d.begin(); dit != d.end(); dit++)
		{
			sum += (*dit);
		}
		sum /= d.size();
		it->score = sum;
		//cout << it->name << "同学的平均分为:" << it->score << endl;
	}
}

void printStu(vector<Student>& v)
{
	for (vector<Student>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "姓名:" << (*it).name << " 分数:" << (*it).score << endl;
	}
}
//谓词
bool SortStu(Student &s1, Student& s2)
{
	//if (s1.score > s2.score)
	//{
	//	Student temp = s1;
	//	s1 = s2;
	//	s2 = temp;
	//}
	return s1.score > s2.score;
}

void stuScore(vector<Student> &v)
{
	//sort(v.begin(), v.end(), SortStu);
	for (int i = 0; i < v.size(); i++)
	{
		for (int j = 0; j < v.size() - i - 1; j++)
		{
			if (v[j].score < v[j + 1].score)
			{
				Student temp = v[j];
				v[j] = v[j + 1];
				v[j + 1] = temp;
			}
		}
	}
	printStu(v);
}

void test()
{
	srand((unsigned int)time(NULL));
	vector<Student> v;
	//创建学生并添加至容器中
	creatStu(v);
	//打分
	putScore(v);
	//排名
	stuScore(v);
}

int main()
{
	test();
	system("pause");
	return 0;
}
2.5 stack容器
	2.5.1 stack容器基本概念
	stack是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口,
stack容器允许新增元素,移除元素,取得栈顶元素,但是除了最顶端外,没有任
何其他方法可以存取stack的其他元素。

	2.5.2 stack没有迭代器
	Stack所有元素的进出都必须符合”先进后出”的条件,只有stack顶端的元素,才有
机会被外界取用。Stack不提供遍历功能,也不提供迭代器。

	2.5.3 stack常用API
	1 stack构造函数
	stack<T> stkT;//stack采用模板类实现, stack对象的默认构造形式: 
	stack(const stack &stk);//拷贝构造函数
	
	2 stack赋值操作
	stack&operator=(const stack &stk);//重载等号操作符
	
	3 stack数据存取操作
	push(elem);//向栈顶添加元素
	pop();//从栈顶移除第一个元素
	top();//返回栈顶元素
	
	4 stack大小操作
	empty();//判断堆栈是否为空
	size();//返回堆栈的大小
#define _CRT_SECURE_NO_WARNINGS
#include<string>
#include<stack>
#include<iostream>
#include<algorithm>
using namespace std;

//栈容器:先进后出
//储存基础数据类型
void test01()
{
	stack<int> s;
	s.push(10);
	s.push(20);
	s.push(30);
	s.push(40);
	s.push(50);

	//输出栈中元素
	while (!s.empty())
	{
		cout << s.top() << endl;
		s.pop();
	}
	cout << "Size:" << s.size() << endl;
}
//存储对象
class Student
{
public:
	Student(string name,int age)
	{
		this->age = age;
		this->name = name;
	}
	string name;
	int age;
};

void test02()
{
	stack<Student> s;
	s.push(Student("aaa", 20));
	s.push(Student("bbb", 21));
	s.push(Student("ccc", 19));

	//输出栈中元素
	while (!s.empty())
	{
		cout << s.top().name<<" "<<s.top().age << endl;
		s.pop();
	}
	cout << "Size:" << s.size() << endl;
}

int main()
{
	//test01();
	test02();

	system("pause");
	return 0;
}
2.6 queue容器
	2.6.1  queue容器基本概念
	Queue是一种先进先出(First In First Out,FIFO)的数据结构,它有两个出口,
queue容器允许从一端新增元素,从另一端移除元素。

	2.6.2 queue没有迭代器
	Queue所有元素的进出都必须符合”先进先出”的条件,只有queue的顶端元素,才有
机会被外界取用。Queue不提供遍历功能,也不提供迭代器。

	2.6.3 queue常用API
	1 queue构造函数
	queue<T> queT;//queue采用模板类实现,queue对象的默认构造形式:
	queue(const queue &que);//拷贝构造函数
	
	2 queue存取、插入和删除操作
	push(elem);//往队尾添加元素
	pop();//从队头移除第一个元素
	back();//返回最后一个元素
	front();//返回第一个元素
	
	3 queue赋值操作
	queue&operator=(const queue &que);//重载等号操作符
	
	4 queue大小操作
	empty();//判断队列是否为空
	size();//返回队列的大小
#define _CRT_SECURE_NO_WARNINGS
#include<string>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;

//队列容器:先进先出
void test01()
{
	queue<int> q;
	q.push(10);
	q.push(20);
	q.push(30);
	q.push(40);
	q.push(50); 

	cout << "front:" << q.front() << endl;
	cout << "back:" << q.back() << endl;

	while (!q.empty())
	{
		cout << q.front() << endl;
		q.pop();
	}

	cout << "Size:" << q.size() << endl;
}
//存储对象
class Student
{
public:
	Student(string name, int age)
	{
		this->age = age;
		this->name = name;
	}
	string name;
	int age;
};

void test02()
{
	queue<Student* > q;
	q.push(new Student("aaa", 18));
	q.push(new Student("bbb", 19));
	q.push(new Student("ccc", 17));
	q.push(new Student("ddd", 21));
	q.push(new Student("eee", 20));

	while (!q.empty())
	{
		//记录指针用于释放内存
		Student* temp = q.front();
		cout << q.front()->name<<" "<< q.front()->age << endl;
		q.pop();
		delete temp;
	}
	cout << "Size:" << q.size() << endl;

}

int main()
{
	//test01();
	test02();

	system("pause");
	return 0;
}
2.7 list容器
	2.7.1 list容器基本概念
	链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过
链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,
结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另
一个是存储下一个结点地址的指针域。
	list的好处是每次插入或者删除一个元素,就是配置或者释放一个元素的空间。因此,
list对于空间的运用有绝对的精准,一点也不浪费。而且,对于任何位置的元素插入或元
素的移除,list永远是常数时间。
	List和vector是两个最常被使用的容器。
	List容器是一个双向链表。
有以下优点:
	1.采用动态存储分配,不会造成内存浪费和溢出
	2.链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
	3.链表灵活,但是空间和时间额外耗费较大

	2.7.2  list容器的迭代器
	List容器不能像vector一样以普通指针作为迭代器,因为其节点不能保证在同一块连续
的内存空间上。List迭代器必须有能力指向list的节点,并有能力进行正确的递增、递减、
取值、成员存取操作。所谓”list正确的递增,递减、取值、成员取用”是指,递增时指向下
一个节点,递减时指向上一个节点,取值时取的是节点的数据值,成员取用时取的是节
点的成员。
	由于list是一个双向链表,迭代器必须能够具备前移、后移的能力
	List有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效

2.7.3  list容器的数据结构
	list容器不仅是一个双向链表,而且还是一个循环的双向链表

2.7.4 常用的list的API
	1 list构造函数
	list<T> lstT;//list采用采用模板类实现,对象的默认构造形式:
	list(beg,end);//构造函数将[beg, end)区间中的元素拷贝给本身。
	list(n,elem);//构造函数将n个elem拷贝给本身。
	list(const list &lst);//拷贝构造函数。
	
	2 list数据元素插入和删除操作
	push_back(elem);//在容器尾部加入一个元素
	pop_back();//删除容器中最后一个元素
	push_front(elem);//在容器开头插入一个元素
	pop_front();//从容器开头移除第一个元素
	insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置。
	insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
	insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。
	clear();//移除容器的所有数据
	erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
	erase(pos);//删除pos位置的数据,返回下一个数据的位置。
	remove(elem);//删除容器中所有与elem值匹配的元素。
	
	
	3 list大小操作
	size();//返回容器中元素的个数
	empty();//判断容器是否为空
	resize(num);//重新指定容器的长度为num,
	若容器变长,则以默认值填充新位置。
	如果容器变短,则末尾超出容器长度的元素被删除。
	resize(num, elem);//重新指定容器的长度为num,
	若容器变长,则以elem值填充新位置。
	如果容器变短,则末尾超出容器长度的元素被删除。
	
	4 list赋值操作
	assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
	assign(n, elem);//将n个elem拷贝赋值给本身。
	list&operator=(const list &lst);//重载等号操作符
	swap(lst);//将lst与本身的元素互换。
	
	5 list数据的存取
	front();//返回第一个元素。
	back();//返回最后一个元素。
	
	6 list反转排序
	reverse();//反转链表,比如lst包含1,3,5元素,运行此方法后,lst就包含5,3,1元素。
	sort(); //list排序
#define _CRT_SECURE_NO_WARNINGS
#include<string>
#include<list>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;

void test()
{
	list<int>::iterator it;
	it++;
	it--;
	//it + 2;//error,证明不是随机访问迭代器,是双向迭代器
}
void printLIst(const list<int>& mylist)
{
	for (list<int>::const_iterator it = mylist.begin(); it != mylist.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

//1.拷贝构造
void test02()
{
	list<int> mylist1(10,6);
	list<int> mylist2(++mylist1.begin(), --mylist1.end());

	printLIst(mylist1);
	printLIst(mylist2);

}
//2.元素的插入和删除
bool myFun(int val)
{
	return val > 400;
}

void test03()
{
	list<int> mylist1;
	mylist1.push_back(10);
	mylist1.push_back(20);
	mylist1.push_back(30);
	mylist1.push_back(40);
	mylist1.push_back(50);
	mylist1.push_front(100);
	mylist1.push_front(200);
	mylist1.push_front(300);
	mylist1.push_front(400);

	vector<int> v;
	v.push_back(1000);
	v.push_back(2000);
	v.push_back(3000);

	mylist1.insert(mylist1.begin(), v.begin(), v.end());
	printLIst(mylist1);

	mylist1.remove(3000);
	printLIst(mylist1);

	//删除大于400的数据
	mylist1.remove_if(myFun);
	printLIst(mylist1);

}
//3.大小操作
void test04()
{
	list<int> mylist1;
	for (int i = 0; i < 5; i++)
	{
		mylist1.push_back(i);
	}
	cout << "Size:" << mylist1.size() << endl;

	if (!mylist1.empty())
		cout << "不为空!" << endl;
	else
		cout << "为空!" << endl;

	mylist1.resize(3);
	printLIst(mylist1);

}

//4.赋值操作和数据存取
void test05()
{
	list<int> mylist1;
	mylist1.assign(10, 10);
	printLIst(mylist1);

	cout << mylist1.front() << endl;
	cout << mylist1.back() << endl;

	list<int> mylist2;
	for (int i = 0; i < 5; i++)
	{
		mylist2.push_back(i);
	}
	printLIst(mylist2);

	mylist2.swap(mylist1);
	cout << "----------------" << endl;
	printLIst(mylist1);
	printLIst(mylist2);
}
//5.反转排序
bool myFunc1(int val, int val1)
{
	return val > val1;
}

void test06()
{
	list<int> mylist1;
	for (int i = 0; i < 5; i++)
	{
		mylist1.push_back(i+10);
	}
	printLIst(mylist1);
	mylist1.reverse();
	printLIst(mylist1);

	//注:list容器不能使用排序算法
	mylist1.sort();
	printLIst(mylist1);
	mylist1.sort(myFunc1);
	printLIst(mylist1);
}

int main()
{
	//test02();
	//test03();
	//test04();
	//test05();
	test06();

	system("pause");
	return 0;
}

3.综合案例:记录进出电梯的人数并打印出来

#define _CRT_SECURE_NO_WARNINGS
#include<string>
#include<list>
#include<vector>
#include<ctime>
#include<queue>
#include<iostream>
using namespace std;

//抽象人员
class Human
{
public:
	string name;
};

void creatHuman(queue<Human>& q1, int num)
{
	string hName = "ABCDEFGHIJKLMN";
	int sum = rand() % 10;
	for (int i = 0; i < sum; i++)
	{
		Human h;

		char buffer[64] = { 0 };
		sprintf(buffer, "%d", num);
		string s(buffer);

		h.name = "第";
		h.name += s;
		h.name += "层";
		h.name += hName[i];

		q1.push(h);
	}
}


void printPushVecotr(vector<Human> &v)
{
	for (vector<Human>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "进出人员名字为:" << (*it).name << endl;
	}
}

int pushHuman(list<Human> &mylist,queue<Human>&q,vector<Human>& pushH)
{
	int temp = 0;//临时变量 记录出电梯人数
	while (!q.empty())
	{
		if (mylist.size() >= 15)
		{
			break;
		}

		Human h = q.front();

		//拷贝到电梯
		pushH.push_back(h);
		//进电梯
		mylist.push_back(h);
		//队列中对头元素出容器
		q.pop();

		temp++;
	}

	return temp;
}

int popHuman(list<Human>& mylist, vector<Human>& popH,int num)
{
	int temp = 0;

	if (num == 17)
	{
		while (!mylist.empty())
		{
			Human h = mylist.front();
			//把出电梯的人拷贝到popH中
			popH.push_back(h);

			mylist.pop_front();//移除出电梯的人
			temp++;

		}
	}
	int n = rand() % 5;
	if (n == 0)
	{
		return temp;
	}
	//当电梯有人,且人数大于等于随机出电梯的人,才让人出电梯s
	if (mylist.size() > 0 && mylist.size() >= n)
	{
		for (int i = 0; i < n; i++)
		{
			Human h = mylist.front();
			//把出电梯的人拷贝到popH中
			popH.push_back(h);

			mylist.pop_front();//移除出电梯的人
			temp++;
		}
	}

	return temp;
}

void test()
{
	srand((unsigned int)time(NULL));
	list<Human> mylist;

	int pushNum = 0;//记录进入人数
	int popNum = 0; //记录出人数

	//记录进出的人
	vector<Human> pushH;
	vector<Human> popH;

	//电梯开始运行
	for (int i = 0; i < 18; i++)
	{
		//创建人员
		queue<Human> q1;
		creatHuman(q1,i);

		//判断是否可以进电梯
		if (mylist.size() <= 15)
		{
			if (i < 17)
			{
				pushNum += pushHuman(mylist,q1, pushH);
			}
		}

		//判断出电梯条件
		if (mylist.size() > 0)
		{
			if (i > 1)
			{
				popNum += popHuman(mylist, popH, i);
			}
		}

		//打印进电梯的人员
		printPushVecotr(pushH);
		cout << "进电梯人数:" << pushNum << endl;
		//打印进电梯的人员
		printPushVecotr(popH);
		cout << "出电梯人数:" << popNum << endl;

	}
}

int main()
{
	test();
	system("pause");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值