C++中的STL

STL有6大组件
重点:容器迭代器算法
简单介绍:适配器、分配器和仿函数
容器(container)

  • 系统帮我们封装好的数据结构(数组array、vector)、链表(单向链表、双向链表)、栈(stack)、队列(queue)、树(map/set)、hash表(hash_map)
  • 每种结构都能装任意类型结构,比如数组可以装int、char、对象等(这就是泛型编程的思想,同一个结构可以装多种类型,也是模板的作用)
  • 主要是数据结构的操作,增删改查数据库。

算法(algorithm)

  • 系统已经帮我们写好了的算法(排序、交换、替换等)
  • 一个算法可以适用于多个容器,(比如排序sort,可以给数组排序,也可以给链表排序)。这也是泛型编程的思想,节省了大量的代码,不然我们的每个容器里都要定义自己的排序。

迭代器(iteration)

  • 连接容器和算法(连接器)

使用STL的好处

  • 节省开发时间,增加开发效率
  • 高移植性:STL是C++标准库,所有的C++编译器都支持
  • 高性能:每个容器的操作、算法的实现都是经过几代大师的修改、优化

1. 容器类

1. string

  string是专门字符串操作的一个类,很强大。
char 与string区别*:
  char*就是指向字符数组首地址的指针,然后系统提供了一个string.h, 这个头文件声明了很多字符串操作函数(strlen、strcat、strcmp、strcpy等).
  string是一个类,它将以上的内容封装到一起,使得字符串的操作更灵活,方式更多,管理更合理。
  我们在使用string这个类的时候不用考虑内存的分配与释放,不用担心越界崩溃问题,因为前人在封装string的时候,已经把几乎所有的情况都考虑到并处理了。

1.1 属性
  容量(capacity()):对于VS,默认容量大小,少于15个则申请15个容量,当多余15个时,以后每多余容量以16个为单位申请空间。对于VC,默认容量大小,少于31个则申请31个容量,当多余31个时,以后每多余容量以32个为单位申请空间。
  容量(reserve()):修改容量,不能变小,只能变大。调用完它之后,容量大小为15+N*16。
length(): 字符串长度,和size()是一样的
size(): 字符串个数,和length()是一样的
resize(n):重新设置字符个数,容量不变
1.2 输出

  • 输出全部: << 对象      c_str()(c_str()返回的是指向字符串首地址的指针)
  • 输出单个字符:1. [ ] 下标运算,越界会崩溃。 2. at(n) 越界会抛出一个异常。

1.3 修改

  • 修改指定元素:[ ] 下标运算,at( ) 运算
  • 中间插入
  • 尾部插入
  • 重新赋值
  • 删除指定元素

1.4. 操作函数

  • 比较 compare
  • 复制 copy
  • 查找子串
  • 返回子串
  • 交换

1.5 string迭代器
  定义一个string对象元素的指针,本质相当于一个char*的指针。定义之后用法和指针是一样的,可以通过迭代器遍历string类的元素,通过迭代器赋值。
  迭代器 :现阶段string类型的迭代器用法和指针是一样的,容器实际有用之处在于可以和算法链接,它适用于所有的容器,即一个通用类型的指针,或者类似叫智能指针。
  迭代器失效:当string对象又申请了一段空间的时候,原来的迭代器失效。

string成员函数涉及到迭代器的:
	iterator begin( ) 
	iterator end( );
	append( )
删除  
	iterator erase(iterator  pos)
	iterator erase(iterator  start, iterator end);
插入
	void insert() // 具体使用方法见下面程序
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
// #pragma warning(disable:XXXX)// 可以不显示相应的警告信息,xxxx为警告码

// 定义
void strDefine()
{
	// 创建对象
	string str;
	//const char* str1 = str.c_str();   // 

	string str1(5, 'a');
	cout << str1.c_str() << endl;

	string str2("abcdefg");
	cout << str2.c_str() << endl;

	string str3("abcdef", 3);
	cout << str3.c_str() << endl;

	string str4("abcdef", 1, 3);
	cout << str4.c_str() << endl;

	string str5(str4);
	cout << str5.c_str() << endl;

}
// 属性
void strProperty()
{
	string str;
	cout << str.capacity() << endl;

	string str1(3,'a');
	cout << "str1.size:" << str1.size() << endl;
	cout << "str1.length:" << str1.length() << endl;
	cout << str1.capacity() << endl;

	string str2("abcdefghi");
	str2.resize(3);
	cout << "str2.size:" << str2.size() << endl;
	cout << "str2.length:" << str2.length() << endl;
	cout << str2.capacity() << endl;
	cout << str2 << endl;

	string str3(str2);
	cout << str3.capacity() << endl;
}
// 输出
void strCout()
{
	string str("abcdefghigk");
	cout << str << endl;      // 注:str不是字符串,是一个对象,能够直接输出是因为string类里面重载了输出

	cout << str.c_str() << endl; // 当创建string对象str的时候,将字符串"abcdefghigk"传入该类,并有一个指针指向这个
								 // 字符串的首地址,c_str()函数的作用就是返回这个指针,即字符串的首地址
	try
	{
		cout << str.at(29) << endl;
	}
	catch (...)
	{
		cout << "out of range" << endl;
	}
}
// 修改
void strChange()
{
	// 修改指定元素

	string str("abcdefgh");
	str[2] = 's';
	str.at(1) = 'z';
	cout << str << endl;
	// 中间插入
	string str1(3,'w');
	str.insert(2, str1);
	cout << str << endl;
	str.insert(6, "ppppp");
	cout << str << endl;
	str.insert(3, str1, 0, 2);	// 在str字符串的下标为3的位置开始插入str1中下标从0到2位置的字符(左闭右开)。
	cout << str << endl;
	str.insert(3, 3, 'q');	// 在str字符串的下标为3的位置开始插入3个q
	cout << str << endl;
	// 尾部插入
	string str2("abcdefg");
	str2 += str;
	str2 += "ppp";
	cout << str2 << endl;
	str2.append(str);
	cout << str2 << endl;
	str2.append("opqres",2);   // 将字符串前两个字符连接到str2字符串后面
	cout << str2 << endl;
	// 重新赋值(覆盖以前的)
	string str3("abcdefg");
	str3 = "def";
	cout << str3 << endl;
	str3 = str;
	cout << str3 << endl;
	cin >> str3;
	cout << str3 << endl;
	str3.assign("asjfla", 3);	// 将字符串前3个字符赋值给str3
	cout << str3 << endl;
	// 删除
	str3.erase(2, 5);			// 删除str3字符串从第二个到第五个元素
	cout << str3 << endl;
	str3.erase(0, str3.length());// 删除str3字符串全部元素
	cout << str3 << endl;
}
// 其他函数
void strFunction()
{
	string str1("acabcdefg");
	string str2("abqc");
	// 比较
	cout << (str1 > str2) << endl; // 从头比较每一个字符,如果是真返回1,否则返回0
	cout << str1.compare("aaf") << endl; // 如果str1>字符串则返回1,相等则返回0,小于则返回-1
	cout << str1.compare(1, 2, str2) << endl; // 用str1中1-2的字符和str2比较
	char arr[6] = { 0 };
	// 复制
	str1.copy(arr, 2, 3); // arr是接收复制的数组,第二个数是复制字符个数,第三个数是开始的下标
	cout << arr << endl;
	// 查找(重点)
	cout << (int)str1.find(str2, 0) << endl; // 查找str1字符串是否包含str2,第二个数是从str1中开始查找的下标,如果找到
									// 返回str1中包含的子串开始的下标,如果没找到则返回-1的补码,强转成int类型即为-1
	cout << (int)str1.find("abc", 0) << endl;// 和上面的意义相同
	// 返回子串
	cout << str1.substr(3, 5) << endl; // 返回str1中从下标3开始的五个字符
	// 交换子串
	str1.swap(str2);
	cout << str1 << endl;
	cout << str2 << endl;
	cout << str1 + str2 << endl;      // 可以加对象
	cout << "sjkafhas" + str2 << endl;// 也可以加子串
	

}
// 迭代器
void funIterator()
{
	string str("abcdefgh");
	// 定义string容器的一个迭代器
	string::iterator ite;	// 就相当于一个指向string对象元素的指针,本质是一个char*类型的指针
	//char* p = str.c_str();
	ite = str.begin(); // begin()和c_str()功能是一样的,返回字符串的首地址

	// 通过迭代器输出元素
	//for (size_t i = 0; i < str.size(); i++)
	//{
	//	/*cout << *ite << endl;
	//	ite++;*/
	//	cout << ite[i] << endl;  // 两种输出方式都可以,ite使用方式和指针一样
	//}
	//for (; ite != str.end(); ite++) // end函数返回的是指向字符串最后一个字符的下一个位置的指针(指向'\0'位置的指针)
	//{
	//	cout << *ite << endl;
	//}

	 通过迭代器赋值
	//for (; ite != str.end(); ite++)
	//{
	//	*ite = 'a' ;
	//	cout << *ite << endl;
	//}
	//ite[-2] = 'w';  // 通过下标运算也可以修改代码
	//cout << str << endl;

	cout << str.capacity() << endl;
	str.append(11, 'b');
	cout << str.capacity() << endl;  // 当迭代器又申请了一段空间后,原来的迭代器失效,需要再次使用begin函数
	ite = str.begin();
	ite[3] = 'z';


}
// string迭代器函数
void testStringIterator()
{
	string str1("abc");
	string str2("def");
	// 尾部插入
	str1.append(str2);
	cout << str1 << endl;
	str1.append(str2.begin()+1,str2.end());
	cout << str1 << endl;
	// 删除元素
	str1.erase(2,5);               // 删除第2-5个元素
	str1.erase(str1.begin() + 2);	// 删除指定位置元素
	cout << str1 << endl;

	// 插入元素
	string str3("zzzzzzz");
	string str4("aaaaaaa");
	str4.insert(str4.begin() + 2, str3.begin() + 2, str3.begin() + 4); // 在str4的第二个位置开始插入str3字符串第2-4位置的字符
	cout << str4 << endl;
}
// 
void fun(char c) // 参数的类型是根据容器元素的类型决定的
{
	cout << c << ' ' ;
}
// string与算法
void funForeach()
{
	string str("qwert");
	for_each(str.begin(), str.end(), fun); // 前两个参数是遍历的开始与结尾,第三个参数是执行的操作

	cout << endl;

	sort(str.begin(), str.end());			// 默认从小到大排序
	for_each(str.begin(), str.end(), fun);

	cout << endl;

	sort(str.begin(), str.end(),greater<char>());// 加上第三个参数就是从大到小排序(greater头文件是functional)
	for_each(str.begin(), str.end(), fun);
}

int main()
{
	// 定义
	//strDefine();
	// 属性
	//strProperty();
	// 输出
	//strCout();
	// 修改
	//strChange();
	// 其他函数
	//strFunction();
	// 迭代器
	//funIterator();
	// string迭代器的使用
	//testStringIterator();
	// string与算法
	funForeach();
	return 0;
}

2. vector 数组

  STL中的数组就是vector,
  向量:内存分配原理跟我们的string是一样的,是连续的空间,空间不够用时,会重新申请一个更大的连续空间,同时原迭代器失效。
  头文件:#include<vector>
  定义向量的对象:vector<参数列表> vec
  参数列表是容器数据的类型,可以是基本的数据类型,比如结构体、指针对象等等。
  注: 对于容器中的元素增、改、查只能是对于存在的元素,否则程序会崩溃。用下标运算只能查找和修改已存在的元素,不能进行赋值,如果要添加新的元素只能通过append等函数操作。
  vector容器的初始容量capacity()定义对象的时候初始化几个就是几个,无参数就初始化为0;
  如果添加元素后空间不够了,则添加现有容量的一半,现有十个就添加五个,现有十三个就添加六个,奇数向下取整。根据编译器的不同,在VC6.0中容量不够时每次增加现有容量的一倍。。
  resize和reserve的区别: 比如一个500ml的瓶子,里面装了300ml的水,那么500就是capacity,300就是size;capacity是容量大小,不一定可以访问,而size是实际有的元素,可以直接访问的。reserve只能修改capacity大小,而resize既可以修改capacity大小也可以修改size大小。
2.1 增删改查之
  尾部添加:push_back()函数。
  中间添加:
    (1)在指定迭代器的位置添加一个数据
    (2)在某个迭代器的某个位置添加num个值为value的元素
    (3)在某个迭代器的某个位置加入另一个向量中的一段
  数组尾部添加的效率非常高,因为它不考虑重新增加新的空间,但是再中间添加的效率非常低。
2.2 增删改查之
  (1)删除最后一个元素:pop_back()
  (2)删除指定位置元素
  (3)删除某一段元素
2.3 增删改查之
  下标运算可以修改元素
  复制函数assign,这个函数会清除以前的元素重新赋值。
具体的实现代码如下所示:

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

// 定义vector容器
void vecConstructure()      // 构造函数
{
	vector<int> vec1;

	vector<int> vec2(5);			// 注意:定义vector容器容量的时候用小括号( ),并且系统将其初始化为0
	for (int i = 0; i < 5; i++)
	{
		cout << vec2[i] << endl;
	}
	vector<int> vec3(5, 12);		// 初始化为5个12
	for (int i = 0; i < 5; i++)
	{
		cout << vec3[i] << endl;
	}
	vector<char> vec4(5, 'a');		// 初始化为5个a 
	for (int i = 0; i < 5; i++)
	{
		cout << vec4[i] << endl;
	}
	vector<char> vec5(vec4);		// 用一个vector对象初始化另一个vector对象,类似于拷贝构造函数,注意类型一定相同
	for (int i = 0; i < 5; i++)
	{
		cout << vec5[i] << endl;
	}
	// 定义迭代器
	vector<int>::iterator vec;

	vector<int>::iterator vec6 = vec3.begin();	// 头迭代器
	vector<int>::iterator vec7 = vec3.end();	// 尾迭代器

	vector<int> vec8(vec6, vec7);
	for (int i = 0; i < 5; i++)
	{
		cout << vec8[i] << endl;
	}
}
// 定义vector容量
void vecCapacity()
{
	vector<int> vec1;
	cout << vec1.capacity() << endl;

	vector<int> vec2(5);
	cout << vec2.capacity() << endl;

	vec2.push_back(1);       // 5 + 5/2 = 7
	cout << vec2.capacity() << endl;

	vec2.push_back(1);       // 7个容量够用
	vec2.push_back(1);		 // 7 + 7/2 = 10
	cout << vec2.capacity() << endl;

	vec2.reserve(12);				// reverse修改容量大小,只能变大不能变小,与string不同的是string的reverse函数
									// 每次增加16个空间,而vector的reverse修改成多少就是多少(比原有空间大才有效)
	cout << vec2.capacity() << endl;

	vector<int> vec3(10);
	vector<int>::iterator vec;		// 
	vec = vec3.begin();
	cout << vec[2] << endl;

	vec3.reserve(12);			// 扩大空间后迭代器失效
	//vec = vec3.begin();
	cout << vec[2] << endl;

}
// 函数测试
void testFun()
{
	vector<int> vec(4);
	vec.reserve(10);     // 修改容量,初始化空间的元素默认赋值为0,用reverse函数扩大的空间没有值
	cout << vec.size() << endl;			// size函数输出的是有效元素个数
	cout << vec.capacity() << endl;		// 输出容器容量大小
	cout << vec[2] << endl;

	vector<int> vec1(5);
	vec1.resize(12);		// 从新设置元素个数,容量不变。
	cout << vec1.size() << endl;			// size函数输出的是有效元素个数
	cout << vec1.capacity() << endl;		// 输出容器容量大小

	cout << vec1.empty();	// 判断对象是否为空,如果是空则返回1,如果不为空则返回0;
}
void fun(int a)
{
	cout << a << ' ';
}
// vector的输出
void vecOut()
{
	vector<int> vec;
	for (int i = 0; i < 10; i++)
	{
		vec.push_back(i);		// push_back就是在对象后面添加一个元素i
	}
	// 输出连续元素
	for (int i = 0; i < 10; i++)
	{
		cout << vec[i] << ' ' << endl;
		cout << vec.at(i) << ' ' << endl;
	}
	// 输出最后一个元素
	cout << vec.back() << ' ' << endl;
	// 用迭代器输出
	vector<int>::iterator ite = vec.begin();
	for (ite; ite != vec.end(); ite++)
	{
		cout << *ite << ' ';   // 迭代器iterator使用方法类似指针
	}
	cout << endl;
	// for_each输出
	for_each(vec.begin(), vec.end(), fun);
}
// vector元素的增加与删除
void vecAdd()
{
	vector<int> vec;
	for (int i = 0; i < 10; i++)
	{
		vec.push_back(i);  // 注意:back函数是输出最后一个元素,push_back函数是在尾部添加元素,pop_back函数是在尾部删除元素
	}
	vec.insert(vec.begin() + 2, 12);	// 在某个位插入元素
	vector<int>::iterator vec1;
	vec1 = vec.begin();		// 迭代器一定要初始化
	for (vec1; vec1 != vec.end(); vec1++)
	{
		cout << *vec1 << ' ';
	}
	cout << endl;
	vec.insert(vec.begin() + 2, 5, 12);	// 在某个位置插入多个元素
	vec1 = vec.begin();					// 迭代器元素增加后一定要再次初始化
	for (vec1; vec1 != vec.end(); vec1++)
	{
		cout << *vec1 << ' ';
	}
	cout << endl;
	vector<int> vec2(5, 1);   // 将vec2初始化为5个1
	vec.insert(vec.begin() + 3, vec2.begin(), vec2.begin() + 3);
	vec.pop_back();			// 删除最后一个元素
	vec1 = vec.begin();					// 迭代器元素增加后一定要再次初始化
	for (vec1; vec1 != vec.end(); vec1++)
	{
		cout << *vec1 << ' ';
	}
	cout << endl;


	vector<int> vec3;
	for (int i = 0; i < 10; i++)
	{
		vec3.push_back(i);
	}
	
	vec3.erase(vec3.begin() + 2);	// 删除指定位置元素
	vector<int>::iterator v1;
	v1 = vec3.begin();			// 迭代器元素个数变化后一定要再次初始化
	for (v1; v1 != vec3.end(); v1++)
	{
		cout << *v1 << ' ';
	}
	cout << endl;
	vec3.erase(vec3.begin() + 2, vec3.begin() + 6);	// 删除某一段元素
	v1 = vec3.begin();			// 迭代器元素个数变化后一定要再次初始化
	for (v1; v1 != vec3.end(); v1++)
	{
		cout << *v1 << ' ';
	}

	// 交换两个对象的元素
	vec.swap(vec3);
}
// vector函数测试
void vecFunction()
{
	vector<int> vec;
	vec.push_back(5);
	vec.push_back(2);
	vec.push_back(12);
	vec.push_back(3);
	vec.push_back(1);
	vec.push_back(8);
	vec.push_back(6);
	vector<int>::iterator vec1;
	vec1 = vec.begin();
	for (vec1; vec1 != vec.end(); vec1++)
	{
		cout << *vec1 << ' ';
	}
	cout << endl;
	sort(vec.begin(), vec.end());					// 默认排序从小到大
	sort(vec.begin(), vec.end(), greater<int>());	// 加上第三个参数排序从大到小   
	vec1 = vec.begin();
	for (vec1; vec1 != vec.end(); vec1++)
	{
		cout << *vec1 << ' ';
	}
	cout << endl;

	// 随机打乱顺序函数
	vector<int> vec2;
	for (int i = 0; i < 6; i++)
	{
		vec2.push_back(i);
	}
	for_each(vec2.begin(), vec2.end(), fun);
	cout << endl;
	srand((unsigned int)time(0));
	random_shuffle(vec2.begin(), vec2.end());	// 随机打乱顺序,和随机函数类似,我们需要设置一个种子
	for_each(vec2.begin(), vec2.end(), fun);
} 
int main()
{
	// 定义vector容器
	//vecConstructure();
	// 定义vector容量
	//vecCapacity();
	// 函数测试
	//testFun();
	// vector输出
	//vecOut();
	// vector的增加
	//vecAdd();
	// vector函数测试
	vecFunction();

	return 0;
}

3. 链表

  双向链表: 比单向链表多了个指向前方的指针。
  与vector的区别: vector是数组,随机访问快,尾部添加元素快,不支持快速插入和删除,插入和删除操作速度非常慢。list随机访问慢,支持快速插入和删除。
  定义list的对象: list<参数列表> ls;
  参数列表可以是指针、结构体…,这里我们程序用结构体演示。

构造函数:

  • 定义多个元素时,系统默认初始化为0
  • 用一个list对象给另一个list对象初始化
  • 用一个list的一段给另一个list初始化(注意list是链表,不支持通过下标偏移移动指针,只支持自加)

定义list的迭代器:
  形式:list<参数列表>::iterator ite; 需要注意的是和string相比,list迭代器多了参数列表,string没有参数列表。其实本质就是参数列表类型的指针。
list的迭代器不能进行加法运算,但是可以自加。

属性:
  没有容量的概念,链表对空间利用率很高,需要一个节点就创建一个节点。
  大小:用size()来输出元素个数;resize()来重新设置元素个数;用empty()可以判断是否有元素。

list的增删改查:
(1)list的增删改查之查:

  • 输出循环:输出全部可以用for_each()。输出单个元素可以通过back()返回最后一个元素,通过front()返回第一个元素。

(2)list的增删改查之增

  • 头部添加:push_front()
  • 尾部添加:push_back()
  • 中间添加:在指定迭代器位置添加一个数据;在指定迭代器位置添加一段值为value的数据;在指定迭代器位置添加另一个迭代器的一段。

(3)list的增删改查之删

  • 头部删除:pop_front()
  • 尾部删除:pop_back()
  • 删除指定元素:iterator erase(iterator loc)可以删除单个元素,iterator erase(iterator start, iterator end)删除一段元素。
  • 删除所有元素:clear()函数。
  • remove()函数可以删除所有跟参数相同的元素。
  • unique()函数可以删除链表中重复的元素

(4)list的增删改查之改

  • assign()函数可以用来给list列表赋值n个相同的值,也可以用另一个链表的一段给list链表赋值(注: 用assign给list赋值的时候会先把原来所有的元素删除)。
  • 也可以直接用 = 将一个链表赋值给另一个链表
  • swap()函数用于交换两个链表的值
  • reverse()函数用于将list中的元素倒转
  • sort()函数用于将list中的元素排序(注: 如果参数是结构体类型则无法直接排序,需要我们在结构体中进行重载)
  • merge()函数可以将两个链表合并,注意合并前两个链表必须是有序的,并且需要重载比较运算符(< 或 >),如果合并之前两个链表是从大到小排列的,则结构体中需要重载 < ,否则需要重载 > 。
  • find()是查找函数,找到后返回值是一个迭代器(当指针使用即可),注意,如果find函数没有找到相关值得话,迭代器返回无效,输出迭代器相关的元素会崩溃。
    上述函数的具体实现方法如下:
#include<iostream>
#include<list>
#include<algorithm>
using namespace std;

struct Node
{
	int a;
	char c;
	//Node(int d,char e)
	//{
	//	this->a = d;
	//	this->c = e;
	//}
};   
struct Node1
{
	int a;
	char c;
	Node1(int d,char e)
	{
		this->a = d;
		this->c = e;
	}

	bool operator == (const Node1& p)
	{
		if (p.a == this->a && p.c == this->c)
		{
			return true;
		}
		return false;
	}
	bool operator < (const Node1& p)
	{
		if (p.a < this->a)
		{
			return true;
		}
		return false;
	}
};
void fun(Node& d)	// 引用类似于一个对象
{
	cout << d.a << ' ' << (int)d.c << endl;
}
void fun1(Node1& d)	// 引用类似于一个对象
{
	cout << d.a << ' ' << (int)d.c << endl;
}
// 定义list容器
void listDefine()
{
	list<struct Node> ls1(6);  // 定义一个list对象
	for_each(ls1.begin(), ls1.end(), fun);
	cout << endl;

	Node node = { 12,'a' }; 
	list<struct Node> ls2(6, node);		// 第一个参数是元素的个数,第二个是元素的对象
	for_each(ls2.begin(), ls2.end(), fun);
	cout << endl;

	list<struct Node> ls3(ls2);			// 用一个list为另一个list初始化
	for_each(ls3.begin(), ls3.end(), fun);
	cout << endl;

	list<struct Node>::iterator ite;
	ite = ls2.begin();			// list是链表,链表不是连续的空间,地址偏移多个没有意义,只支持自加
	ite++;
	ite++;
	list<struct Node> ls4(ite, ls2.end()); // 用另一个对象中的一段给list对象初始化
	for_each(ls4.begin(), ls4.end(), fun);
	cout << endl;

	ite = ls1.begin();
	ite++;
	//ite = ite + 2;		// list是链表,链表不是连续的空间,地址偏移两个没有意义

}
// list函数测试
void listFunction()
{
	Node node = { 12,'a' };			// 定义结构体元素的值
	list<Node> ls(6, node);			// 定义6个节点
	for_each(ls.begin(), ls.end(), fun);
	cout << ls.size() << endl;

	ls.resize(10);					// 如果修改的比原来小则减少ls中的元素,如果修改的比原来多则将扩充的初始化为0
	for_each(ls.begin(), ls.end(), fun);
	cout << ls.size() << endl;

	ls.empty();
}
// list的输出和增加
void listOutAdd()
{
	Node node = { 12, 'a' };
	//Node node (12, 'a' );
	list<Node> ls1(6, node);
	//cout << ls1.back().a << ' ' << ls1.back().c << endl;		// 输出最后一个元素
	//cout << ls1.front().a << ' ' << ls1.front().c << endl;	// 输出第一个元素
	//for_each(ls1.begin(), ls1.end(), fun);

	list<Node> ls2;
	Node no = { 16,'c' };
	ls2.push_front(no);	// 头部添加
	ls2.push_back(no);	// 尾部添加
	no = { 12,'p' };
	ls2.push_front(no);	// 头部添加
	for_each(ls2.begin(), ls2.end(), fun);
	cout << endl;
	no = { 22,'z' };
	list<Node>::iterator ite;
	ite = ls2.begin();
	ite++;
	ls2.insert(ite, no);					// 在第二个位置插入节点
	for_each(ls2.begin(), ls2.end(), fun);
	ite = ls2.begin();
	ite++; 
	ite++;
	ls2.insert(ite, 3, no);					// 在第三个位置插入3个节点
	cout << endl;
	for_each(ls2.begin(), ls2.end(), fun);
}
// list的删除和修改
void listDelChange()
{
	list<Node1> ls;
	ls.push_back(Node1(18, 'k'));		// 为结构体添加构造函数后,可以用这种方法为list对象添加元素
	ls.push_front(Node1(19, 'k'));
	ls.push_back(Node1(20, 'k'));
	ls.push_back(Node1(18, 'k'));
	ls.push_front(Node1(36, 'k'));
	ls.push_front(Node1(18, 'k'));
	ls.push_back(Node1(20, 'k'));
	ls.push_back(Node1(18, 'k'));
	ls.push_front(Node1(36, 'k'));
	ls.push_front(Node1(18, 'k'));
	//for_each(ls.begin(), ls.end(), fun1);
	//cout << endl;
	//ls.pop_back();				// 头删除
	//ls.pop_front(); 			// 尾删除
	//for_each(ls.begin(), ls.end(), fun1);
	//cout << endl;
	//list<Node1>::iterator ite;
	//ite = ls.begin();
	//ite++;
	//ls.erase(ite);			// 删除第二个元素
	//ls.erase(--ls.end());			// 删除最后一个元素,end()函数指向的是最后一个元素的下一个位置
	//for_each(ls.begin(), ls.end(), fun1);
	//cout << endl;
	//ite = ls.begin();
	//ite++;
	//ls.erase(ite, --ls.end()); // 删除一段元素
	//for_each(ls.begin(), ls.end(), fun1);
	//cout << endl;

	//ls.clear();				// 删除所有元素
	ls.remove(Node1(18, 'k'));	// 涉及到结构体类型的比较一定哟啊函数重载
	//for_each(ls.begin(), ls.end(), fun1);
	cout << endl;
	ls.push_back(Node1(18, 'k'));
	ls.push_front(Node1(18, 'k'));
	ls.unique();					// 删除list中重复的元素
	//for_each(ls.begin(), ls.end(), fun1);

	ls.assign(3, Node1(1, 'o'));			// assign()函数用来赋值list列表,直接将原来的list清空,赋值新的
	for_each(ls.begin(), ls.end(), fun1);
	cout << endl;

	list<Node1> ls1;
	ls1.push_back(Node1(3, 'a'));
	ls1.push_back(Node1(3, 'a'));
	ls1.push_back(Node1(3, 'a'));
	ls1.push_back(Node1(3, 'a'));
	ls1.push_back(Node1(3, 'a'));
	ls1.push_back(Node1(3, 'a'));
	ls1.push_back(Node1(3, 'a'));

	list<Node1>::iterator ite;
	ite = ls1.begin();
	ite++;
	ite++;
	ls.assign(ite,ls1.end());			// assign()函数,用一个链表的一段给另一个链表赋值(注;赋值前把原有链表清空)
	for_each(ls.begin(), ls.end(), fun1);

}
// list的合并
void listMerge()
{
	list<Node1> ls1;
	ls1.push_back(Node1(1, 'a'));
	ls1.push_back(Node1(5, 'a'));
	ls1.push_back(Node1(3, 'a'));
	ls1.push_back(Node1(4, 'a'));	
	ls1.push_back(Node1(2, 'a'));
	ls1.push_back(Node1(6, 'a'));

	list<Node1> ls2;
	ls2.push_back(Node1(7, 'a'));
	ls2.push_back(Node1(8, 'a'));
	ls2.push_back(Node1(9, 'a'));
	ls2.push_back(Node1(10, 'a'));
	ls2.push_back(Node1(11, 'a'));
	ls2.push_back(Node1(12, 'a'));

	ls1.swap(ls2);								// 交换两个list的内容
	ls1.swap(ls2);
	for_each (ls1.begin(), ls1.end(), fun1); 
	cout << endl;
	for_each (ls2.begin(), ls2.end(), fun1);

	ls1.reverse();								// 将list中的元素倒转
	cout << endl;
	for_each(ls1.begin(), ls1.end(), fun1);

	ls1.sort();						// 因为排序的是结构体类型,系统无法直接比较,因此我们需要在结构体中进行重载
	cout << endl;
	for_each(ls1.begin(), ls1.end(), fun1);

	ls1.sort();
	ls2.sort();
	ls1.merge(ls2);		// 合并的两个链表一定是有序的,如果合并之前两个链表是从大到小的则需要重载< ,反之需要重载 >
	cout << endl;
	for_each(ls1.begin(), ls1.end(), fun1);
	cout << endl;
	for_each(ls2.begin(), ls2.end(), fun1);

}
// 查找函数
void listFind()
{
	list<Node1> ls1;
	ls1.push_back(Node1(1, 'a'));
	ls1.push_back(Node1(2, 'a'));
	ls1.push_back(Node1(3, 'a'));
	ls1.push_back(Node1(4, 'a'));
	ls1.push_back(Node1(5, 'a'));
	ls1.push_back(Node1(6, 'a'));
	ls1.push_back(Node1(7, 'a'));

	list<Node1>::iterator ite = find(ls1.begin(), ls1.end(), Node1(3, 'a'));			// find是一个算法,不需要对象调用,find函数返回的是一个迭代器
	cout << ite->a << ' ' << ite->c << endl;  // ite相当于一个指针,调用元素时需要用->
	// 注: 如果find函数没有找到相关元素,则迭代器返回无效,输出的话程序会崩溃
}

int main()
{
	// 定义list容器 
	//listDefine();
	// list函数测试
	//listFunction();
	// list的输出和增加
	//listOutAdd();
	// list的删除和修改
	//listDelChange();
	// list的合并
	//listMerge();
	// 查找函数
	listFind();

	return 0;
}

4. 双端队列

  • 内存比较
      1. vector:连续的内存空间,类似于数组
      2. list:离散的内存空间,类似于链表
      3. deque:段连续空间(每一段512字节)
  • 功能比较
      1. vector:插入效率低,随机访问效率高,不支持头添加,支持尾添加。
      2. list:插入效率高,随机访问效率低,支持头添加和尾添加。
      3. deque:随机插入、删除效率不高,支持随机访问(比vector慢因为要做堆跳转),迭代器结构复杂,会降低访问效率;支持头添加和尾添加。
  • 使用选择
      1. 随机访问频率高的用vector
      2. 需要经常插入删除的用list
      3. 需要随机访问+头添加的用deque,deque比vector多了一个头添加,比list多了一个随机访问,(deque支持下标访问和at()访问,但是效率不如vector高。支持内部插入和删除操作,但是效率不如list高)。
  • 函数对比
      1. 对比vector没有 capacity()和reserve()
      2. 多了push_front() ,push_back() 和 pop_front() , pop_back() ;
      3. 其他的和其他函数一样

5. map

map介绍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值