C++语言学习笔记11

C++语言学习笔记11,第1张

C++语言学习笔记11
      • 函数模板
      • 函数模板之冒泡排序
      • 类模板各种情况1.0
      • 类模板各种情况2.0
      • STL标准模板库
      • 标准模板库之容器
        • sequence序列容器
          • list 链表
          • vector 动态数组/向量
          • deque 队列
        • associative关联容器
          • map
      • 容器查阅文档见下:
        • sequence序列容器
          • list
          • vector
          • deque
        • associative关联容器
          • map
          • set
      • 容器-迭代器-算法 ——关系表

函数模板
#include
#include
using namespace std;

//	template:定义模板的关键字
//	typename:定义模板类型的关键字
//	TT:通用的类型,在调用函数进行使用的时候会根据所给的参数类型自动匹配
//	:模板的参数列表,需要多个参数的话就加逗号继续写,比如template
//	PS:要紧挨着需要使用函数模板的函数(上下行,中间尽量别写乱七八糟的东西)
//	   如果函数声明和定义是分开的,那么函数模板的那句话在声明和定义的部分都要加上。


template<typename TT> TT Add(TT a, TT b) { TT c = a + b; return c; } template<typename TT,typename KK> TT Add(TT a, TT b, KK d) { TT c = a + b; return c; } //double Add(double a, double b) { // return a + b; //} template<typename TT> void show(TT a, int b = 10); //函数体加了模板但函数内无,无法自动推导TT的类型~,所以要指定类型 template<typename TT=int> TT show1() { cout << "show1" << endl; return 0; } // c++98编译失败(仅允许在类模板上使用默认模板参数),但目前c++11已经解除该限制,C++11支持了函数模板的默认模板参数,此处可以编译通过。


// PS:尽管C++11支持了函数模板的默认模板参数,不过在语法上,两者还是存在区别:类模板在为多个默认模板参数声明指定默认值时,必须遵照“从右往左”的规则进行指定。


而这个规则对函数模板来说并不是必须的~对于函数模板来说,默认模板参数的位置则比较随意~ // 如果能够从函数实参中推导出类型的话,那么默认模板参数就不会被使用,反之,默认模板参数则可能会被使用。


//C++98的解决方式: //template //TT show1() { // cout << "show1" << endl; // return 0; //} // //调用时在函数后面加上<默认的参数类型>使用,如:show1(); //函数内加了模板 但函数体无 无法自动推导TT的类型~,所以要指定类型,调用时在函数后面加上<默认的参数类型>使用 template<typename TT> void show2(int a) { TT c = 30; cout << "show2" << c << endl; } template<typename TT> void show3(TT a) { TT c = a; cout << "show3" << c << endl; } template<typename TT, typename KK> void show4(TT a) { TT c = a; KK d = 10; cout << "show4" << c << d << endl; } int main() { int a = 10, b = 20; cout << Add(a, b) << endl; double c = 10.1, d = 10.2; cout << Add(c, d) << endl; Add(a, b, d);//此时根据参数匹配,TT就会是int类型,KK是double类型~ char k = 50; show(k, 20); show1(); //RTTI 动态类型识别 //cout << typeid(show1()).name() << endl; //cout << typeid(show1()).name() << endl; show2<double>(48); show3(48); //默认推导是int类型 但想用别的类型来存 也可以用<类型>的方式 show3<char>(48); //show4(48); //报错,函数模板参数列表多个,那类型也就需要指定多个~如下: show4<char, double>(48); system("pause"); return 0; } template<typename TT> void show(TT a, int b) { cout << a << endl; cout << b << endl; }

函数模板参考资料(注意下C++11的一些更新~)

函数模板之冒泡排序
#include
using namespace std;
#include 
#include 

template<typename TT>
bool rule(TT a, TT b)
{
	return a < b;
}

bool rule1(int a, int b)
{
	return a > b;
}

bool rule2(double a, double b)
{
	return a > b;
}

template<typename TT>
void BubbleSort(TT* pArr, int length, bool(*p_fun)(TT, TT)) {
	if (pArr == NULL || length <= 0) {
		return;
	}
	for (int i = 0; i < length - 1; i++)
	{
		for (int j = 0; j < length - 1 - i; j++)
		{
			//if (pArr[j] < pArr[j + 1])	//从大到小
			//if (pArr[j] > pArr[j + 1])	//从小到大
			if ((*p_fun)(pArr[j], pArr[j + 1])) 
			{
				TT temp = pArr[j];
				pArr[j] = pArr[j + 1];
				pArr[j + 1] = temp;
			}
		}
	}
}

//void show(int a) {	//参数是每个结点里值的类型~
//
//}
//
//list lst;
//lst.push_back(1);
//lst.push_back(2);
//::for_each(lst.begin(), lst.end(), &show);
::for_each注意要使用头文件#include 噢~
次函数的三个参数是 头 尾 自己指定写的函数,参考该思想来改写冒泡排序,以求能达到能够自己选择是从大到小还是从小到大进行排序~


int main() {

	int arr[10] = { 2,7,8,1,0,9,6,3,4,5 };

	BubbleSort(arr, 10, &rule<int>);
	for (int val : arr)	//	从arr里面取出元素放在val里,可以有效避免数组越界
						//	(数组越界即:arr[i],但是i的值大于数组的大小)
	{
		cout << val << "	";
	}cout << endl;

	BubbleSort(arr, 10, &rule1);
	for (int val : arr)
	{
		cout << val << "	";
	}cout << endl;


	double arr1[10] = { 2.2,7.7,8.8,1.1,0.1,9.9,6.6,3.3,4.4,5.5 };

	BubbleSort(arr1, 10, &rule);
	for (double val : arr1)
	{
		cout << val << "	";
	}cout << endl;

	BubbleSort(arr1, 10, &rule2) ;
	for (double val : arr1)
	{
		cout << val << "	";
	}cout << endl;

	system("pause");
	return 0;
}
类模板各种情况1.0
#include 
using namespace std;
#include 


//从右往左依次指定,不能间断
//如果类模板参数列表都已经默认指定,如:template,那么如果函数调用时不想使用默认要重新指定的话,要么两个都重新指定,要么重新指定KK,不会出现指定TT而KK默认的情况,因为从右往左依次指定,不能间断。


//template template<typename TT=int, typename KK = double> class CTest { public: TT m_a; KK m_k; public: CTest() { m_a = 10; } CTest(TT t,KK k) { m_a = t; m_k = k; } public: void show(TT tt) { TT t = 20; cout << t << " " << typeid(t).name() << endl; cout << tt << " " << typeid(tt).name() << endl; } void get() { cout << m_a << " " << typeid(m_a).name() << endl; cout << m_k << " " << typeid(m_k).name() << endl; } void play(); void play1(TT t, KK k); template<typename MM> void Test(MM mm) { MM m = 30; cout << m << " " << mm << " " << typeid(m).name() << endl; } template<typename HH> void Test1() { HH hh = 20; cout << hh << " " << typeid(hh).name() << endl; } template<typename NN> void Name(TT t, KK k); }; //void CTest::play() { //报错:缺少类模板的参数列表 //void CTest::play() { // cout << m_a << " " << typeid(m_a).name() << endl; // cout << m_k << " " << typeid(m_k).name() << endl; //} //不能在类外部的类模板成员声明上指定默认的模板参数类型 //template template<typename TT , typename KK> void CTest<TT,KK>::play() { cout << m_a << " " << typeid(m_a).name() << endl; cout << m_k << " " << typeid(m_k).name() << endl; } template<typename TT, typename KK> void CTest<TT, KK>::play1(TT t, KK k) { cout << m_a+t << " " << typeid(m_a).name() << endl; cout << m_k+k << " " << typeid(m_k).name() << endl; } //类模板+函数模板时 注意模板声明的顺序 template<typename TT, typename KK> template<typename NN> void CTest<TT, KK>::Name(TT t, KK k) { NN n = 50; cout << m_a << " " << typeid(m_a).name() << endl; cout << m_k << " " << typeid(m_k).name() << endl; cout << n << " " << typeid(n).name() << endl; } int main() { CTest tst; 报错:因为不知道TT的类型,所以用类创建对象时也无法确定空间 //CTest tst; 能明显看出类似于list lst; 实际上封装好的list也是一个模板类~ //cout << tst.m_a << endl; //tst.show(10); //CTest tst2(3.14,'A'); //tst2.get(); //CTest tst2(3.14, 5); //tst2.get(); //CTest tst2(3.14, 10); 指定了那就用指定的,没指定就用默认的 //tst2.get(); CTest< > tst(20, 3.14); //类模板参数列表多个,此时想要都用默认的时候注意要加< >,如果不加也无法编译通过 tst.get(); tst.play(); CTest<char, int> tst2('A', 30); tst2.play(); //报错:void CTest::play() ,该函数没有实现,实际上我们所实现的只有void CTest::play() ,那么如何让play函数具备拓展复用性? //解决方法:在play函数上加上函数模板,注意该处的参数列表不要设置默认类型噢~ CTest<char, int> tst3('A', 30); tst3.play1('0', 20); tst3.Test(10); tst3.Test1<long>(); tst3.Name<long>('0',5); system("pause"); return 0; }

类模板各种情况2.0
#include 
using namespace std;
#include 

template<typename TT>
class CTestAA
{
public:
	TT m_T;
public:
	CTestAA() {
		m_T = 20;
	}
};

template<typename KK>
class CTestBB
{
public:
	CTestAA<KK> m_a;
};

template<typename MM,typename NN>
class CTestCC 
{
public:
	MM m_m;
	NN m_n;

	CTestCC(MM m, NN n) {
		m_m = m;
		m_n = n;
	}
};

int main() {

	CTestBB<int> tstBB;
	cout << tstBB.m_a.m_T << "	" << typeid(tstBB.m_a.m_T).name() << "	" << typeid(tstBB.m_a).name() << endl;

	CTestAA<int>	aa;
	CTestCC<CTestAA<int>, int> tstCC(aa,10);
	cout << tstCC.m_m.m_T << "	" << typeid(tstCC.m_m.m_T).name() << "	" << tstCC.m_n << "	" << typeid(tstCC.m_n).name() << endl;

	system("pause");
	return 0;
}
STL标准模板库
  • STL——Standard Template Library——标准模板库

  • 六组件

    • 容器 Containers
    • 迭代器 Iterators
    • 算法 Algorithms
    • 容器适配器 Container Adapters
    • 分配器/空间适配器 Allocators
    • 仿函数 Function Objects
标准模板库之容器
  • sequence序列容器:list/vector/deque

    • 保持了元素在容器中的原始位置,允许在容器中指定插入的位置,每个元素都有固定的位置,取决于插入的时间地点,和元素的值无关。


  • associative关联容器:map/set/hash_map

    • 元素插入的位置取决于特定的排序规则。


sequence序列容器 list 链表
#include 
using namespace std;
#include 
#include 


bool rule(int a, int b) {
	return a > b;
}

void show(int a) {
	cout << a << "  ";
}

int main() {
	
	list<int> lst;
	lst.push_back(1);
	lst.push_back(8);
	lst.push_back(8);
	lst.push_back(5);
	lst.push_back(3);
	lst.sort();
	//lst.sort(&rule);

	//::for_each(lst.begin(), lst.end(), &show); cout << endl;

	//lst.remove(3);		//移除固定的值
	//::for_each(lst.begin(), lst.end(), &show); cout << endl;

	//lst.unique();		//连续且相同 只保留一个
	//::for_each(lst.begin(), lst.end(), &show); cout << endl;

	//lst.sort();			//默认升序,可通过设定规则确认升序降序
	//::for_each(lst.begin(), lst.end(), &show); cout << endl;

	//lst.reverse();		//翻转
	//::for_each(lst.begin(), lst.end(), &show); cout << endl;

	//lst.sort(&rule);	//指定规则降序排序
	//::for_each(lst.begin(), lst.end(), &show); cout << endl;

	list<int> lst2;
	lst2.push_back(60);
	lst2.push_back(20);
	lst2.push_back(50);
	lst2.sort();
	//lst2.sort(&rule);

	//::for_each(lst2.begin(), lst2.end(), &show); cout << endl;

	//lst.splice(++lst.begin(), lst2);	//整个
	//::for_each(lst.begin(), lst.end(), &show); cout << endl;
	//::for_each(lst2.begin(), lst2.end(), &show); cout << endl;	//lst2插入到lst后,lst2重载为空~ 所以该行输出无内容
	
	//lst.splice(++lst.begin(), lst2, ++lst2.begin());	//20
	//::for_each(lst.begin(), lst.end(), &show); cout << endl;
	//::for_each(lst2.begin(), lst2.end(), &show); cout << endl;

	//lst.splice(++lst.begin(), lst2, ++lst2.begin(), lst2.end());	//20,50
	//::for_each(lst.begin(), lst.end(), &show); cout << endl;
	//::for_each(lst2.begin(), lst2.end(), &show); cout << endl;

	//lst.splice(++lst.begin(), lst, --lst.end());	//结尾的1插入到首8的后面
	//::for_each(lst.begin(), lst.end(), &show); cout << endl;
	//::for_each(lst2.begin(), lst2.end(), &show); cout << endl;

	//lst.push_back(8);
	//lst.push_back(5);
	//lst.push_back(3);
	//::for_each(lst.begin(), lst.end(), &show); cout << endl;
	//8 5 1 8 5 3

	//lst.splice(++lst.begin(), lst, ++(++lst.begin()), lst.end());	
	 1 8 5 3插入到8后面
	//::for_each(lst.begin(), lst.end(), &show); cout << endl;
	//::for_each(lst2.begin(), lst2.end(), &show); cout << endl;

	//lst.splice(++lst.begin(), lst, lst.begin(), --lst.end());	
	//			//不报错但实际上会出现错误,也就是说范围不能是整个原链表~
	//::for_each(lst.begin(), lst.end(), &show); cout << endl;
	//::for_each(lst2.begin(), lst2.end(), &show); cout << endl;

	//lst.merge(lst2);	
	//			//两个list的内容都必须先经过递增排序,该函数是合并两个链表整体进行排序,默认的是递增~也可以指定降序,如果降序的话那么两个list的内容先需要经过降序排序
	//::for_each(lst.begin(), lst.end(), &show); cout << endl;

	//lst.merge(lst2, &rule);
	//::for_each(lst.begin(), lst.end(), &show); cout << endl;

	lst.swap(lst2);		//交换两链表内的元素 写法一~
	swap(lst, lst2);	//写法二~
	::for_each(lst.begin(), lst.end(), &show); cout << endl;
	::for_each(lst2.begin(), lst2.end(), &show); cout << endl;

	system("pause");
	return 0;
}
vector 动态数组/向量
#include 
using namespace std;
#include 
#include 

//vector 动态数组

void show(int a) {
	cout << a << "	";
}

int main() {
	
	//vector vec;	//	size<=容量
	//cout << vec.size() << "	" << vec.capacity() << endl;	// 0 0

	//vector vec(2);	//	构造元素的数量但未给出初始化的值,因此默认是0
	//cout << vec.size() << "	" << vec.capacity() << endl;	// 2 2
	//vector::iterator ite = vec.begin();
	//while (ite != vec.end())
	//{
	//	cout << *ite << "	";
	//	ite++;
	//}cout << endl;	// 0 0

	vector<int> vec(2, 4);	//	构造元素的数量并给出初始化的值4
	cout << vec.size() << "	" << vec.capacity() << endl;	// 2 2
	vector<int>::iterator ite = vec.begin();
	while (ite != vec.end())	//遍历 方法1
	{
		cout << *ite << "	";
		ite++;
	}cout << endl;	// 4 4

	vec.push_back(1);
	vec.push_back(2);
	vec.push_back(3);

	for (int i = 0; i < vec.size(); i++)	//遍历 方法2
	{
		cout << vec[i] << "	";
	}cout << endl;	

	::for_each(vec.begin(), vec.end(), &show);	//遍历 方法3
	cout << endl;

	cout << vec.size() << "	" << vec.capacity() << endl;	
		// 5 6	
		//为什么是6不是5?其容量的扩充有其自己的规则,不是加一个元素就加一个容量噢~

	//cout << vec.front() << endl;
	//cout << vec.back() << endl;

	//vec.pop_back();
	//::for_each(vec.begin(), vec.end(), &show);
	//cout << endl;
	//cout << vec.size() << "	" << vec.capacity() << endl;	
	//	//	4 6
	//	//	删除尾部的元素时,其容量不会变化

	只有pop_back尾删除和push_back尾添加~没有pop_front之类的噢

	//vec.insert(++vec.begin(), 5);	//4后加5
	//::for_each(vec.begin(), vec.end(), &show);
	//cout << endl;

	//vec.insert(++vec.begin(), 2, 9);	//4后加2个9
	//::for_each(vec.begin(), vec.end(), &show);
	//cout << endl;

	//vec.erase(vec.begin());	//删除第一个元素
	//::for_each(vec.begin(), vec.end(), &show);
	//cout << endl;

	vector<int>::iterator ite1 = ++vec.begin();		//ite1指向4
	//vec.erase(ite1);	
	//ite1还是指向原位置,但4被删除,后面的1往前移,所以ite1指向的是1,和链表不同,链表节点删除后,指向的ite必须要用东西接一下,否则就遗失了,但此处无须用东西接,其还是指向那个位置
	ite1 = vec.erase(ite1);//手贱想要接一下也会是一样的结果,还是1~
	::for_each(vec.begin(), vec.end(), &show);
	cout << endl;

	vec.clear();	//size=0,但容量不变噢!
	cout << vec.size() << "	" << vec.capacity() << endl;

	//Iterator find(起始位置,结束位置,查找的元素值)	//找到指定的值的位置
	//PS:不是vector的成员而是c++提供的一个函数噢!
	//另外,vector内部也没有提供像链表一样的sort排序的功能,但是算法中提供::sort()函数。


vector<int>* pVec = new vector<int>(2, 3); //这样new也是被允许哒,不过这个在堆区啦,上面那些是在栈区的噢~ cout << pVec->size() << " " << pVec->capacity() << endl; system("pause"); return 0; }

deque 队列
#include 
using namespace std;
#include 
#include 
#include 
#include 

void show(int a) {
	cout << a << "	";
}

int main() {

	deque<int> de;
	de.push_back(3);
	de.push_back(6);
	de.push_back(2);
	de.push_back(5);
	de.push_back(9);

	//遍历的几种方式~
	for (int i = 0; i < de.size(); i++) 
	{
		cout << de[i] << "	";
	}cout << endl;

	::for_each(de.begin(), de.end(), &show);
	cout << endl;

	de.push_front(1);
	de.push_front(2);
	
	deque<int>::iterator ite = de.begin();
	while (ite != de.end())
	{
		cout << *ite << "	";
		ite++;
		//ite += 2;
	}cout << endl;

	//list lst;
	//lst.begin() += 2;	//list没有重载+=  所以报错  可以利用advance解决(迭代器加~)
	//vector	vec;
	//vec.begin() += 2;	//vector重载了+=

	ite = de.begin();				//ite 指向头
	//::advance(ite, 3);			//ite 偏移3
	//::advance(ite, de.size() - 1);//ite 偏移到最后一个元素
	//::advance(ite, de.size);		//出界~ 报错了噢
	cout << *ite << endl;


	for (int val : de)
	{
		cout << val << "	";
	}cout << endl;

	cout << endl;
	de.pop_back();
	::for_each(de.begin(), de.end(), &show);
	cout << endl;
	de.pop_front();
	::for_each(de.begin(), de.end(), &show);
	cout << endl;

	cout << "size:" << de.size() << endl;

	de.insert(++de.begin(), 10);
	::for_each(de.begin(), de.end(), &show);
	cout << endl;

	cout << "size:" << de.size() << endl;

	de.erase(++de.begin());
	::for_each(de.begin(), de.end(), &show);
	cout << endl;

	cout << "size:" << de.size() << endl;

	de.resize(de.size() + 2);
	cout << "size:" << de.size() << endl;
	::for_each(de.begin(), de.end(), &show);
	cout << endl;

	de.resize(de.size() - 4);
	cout << "size:" << de.size() << endl;
	::for_each(de.begin(), de.end(), &show);
	cout << endl;
	
	de.clear();
	cout << "size:" << de.size() << endl;
	::for_each(de.begin(), de.end(), &show);
	cout << endl;

	system("pause");
	return 0;
}
associative关联容器 map
#include
#include
#include
#include
using namespace std;


//	如何确定是关联性容器还是序列性容器?
//	序列性容器:元素跟插入的时间和地点,有固定的位置。


// 关联性容器:元素的位置和插入无关,有其特定的排列顺序 void show(pair<string, int> pr) { cout << pr.first << " " << pr.second << endl; } int main() { map<string, int> mm; mm["DD"] = 100; mm["CC"] = 200; mm["UU"] = 300; mm["SS"] = 400; //遍历 //根据键值自动排序~ map<string, int>::iterator ite = mm.begin(); while (ite != mm.end()) { cout << (*ite).first << " " << (*ite).second << endl; ite++; } ::for_each(mm.begin(), mm.end(), &show); //通过键值找到实值 不再像序列性容器一样去遍历再查找~ cout << mm["DD"] << endl; //cout << mm["OO"] << endl; // 不存在则输出0 查找效率(log2n 2为底n的对数) //注意!此处mm["OO"]如果没有,那么就会自动加一个"OO" 0 if (mm["DD"]) { cout << mm["DD"] << endl; } else { cout << "不存在" << endl; } //if (mm["OO"]) { //注意!此处mm["OO"]如果没有,那么就会自动加一个"OO" 0 // cout << mm["OO"] << endl; //} //else { // cout << "不存在" << endl; //} map<string, int>::iterator ite1 = mm.find("CC"); cout << (*ite1).first << " " << (*ite1).second << endl; //两种写法~ cout << ite1->first << " " << ite1->second << endl; map<string, int>::iterator ite2 = mm.find("OO"); //找不到OO 会返回一个指向end()的迭代器 if (ite2 != mm.end()) { cout << (*ite2).first << " " << (*ite2).second << endl; cout << ite2->first << " " << ite2->second << endl; } cout << endl; ::for_each(mm.begin(), mm.end(), &show); cout << endl; pair<string, int> pr1("II", 600); mm.insert(pr1); ::for_each(mm.begin(), mm.end(), &show); cout << endl; pair<string, int> pr2("PP", 500); mm.insert(mm.begin(), pr2); //依然会自动按照键值排序,和给定的mm.begin()位置没有关系 //mm.begin()只是给出的一个起始搜索的位置(可以提高程序的效率),但该位置并不一定是真正元素插入的位置 ::for_each(mm.begin(), mm.end(), &show); cout << endl; map<string, int>::iterator ite3 = mm.find("II"); mm.erase("II"); ::for_each(mm.begin(), mm.end(), &show); cout << endl; if (mm.count("PP")) { cout << mm["PP"] << endl; } else { cout << "不存在" << endl; } cout << endl; if (mm.count("II")) { cout << mm["II"] << endl; } else { cout << "不存在" << endl; } cout << endl; cout << mm.size() << endl; cout << endl; ::for_each(mm.begin(), mm.end(), &show); cout << endl; //map::iterator ite4 = mm.lower_bound("UU"); //返回大于等于该键值的迭代器 有UU 返回UU map<string, int>::iterator ite4 = mm.lower_bound("EE"); //返回大于等于该键值的迭代器 没有EE 返回EE后面的有的键值 此处有CC DD UU SS PP 所以返回PP cout << ite4->first << " " << ite4->second << endl; cout << endl; map<string, int>::iterator ite5 = mm.upper_bound("PP"); //返回大于该键值的迭代器 CC DD PP SS UU 所以此处返回SS cout << ite5->first << " " << ite5->second << endl; cout << endl; mm["SS"] = 5000; ::for_each(mm.begin(), mm.end(), &show); cout << endl; map<string, int>::iterator ite6 = mm.find("SS"); //ite6->first = "MM"; //不可以改键值!!只可以改实值!! ite6->second = 1; ::for_each(mm.begin(), mm.end(), &show); }

容器查阅文档见下: sequence序列容器 list vector deque associative关联容器 map set 容器-迭代器-算法 ——关系表

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/567304.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)

保存