前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++ STL 标准模板库(容器总结)算法

C++ STL 标准模板库(容器总结)算法

作者头像
微软技术分享
发布2022-12-28 17:26:02
2.3K0
发布2022-12-28 17:26:02
举报
文章被收录于专栏:Visual C++ 编程技术实践

C++ 标准模板库STL,是一个使用模板技术实现的通用程序库,该库由容器container,算法algorithm,迭代器iterator,容器和算法之间通过迭代器进行无缝连接,其中所包含的数据结构都是目前最优解,该库既能保证软件代码的高可复用性,又能保证代码具有相当高的执行效率,STL库是ANSI/ISO的C++标准的具体实现,任何标准库的实现都是以源码形式释出的.

STL是C++的一部分,STL可分为容器(containers)、迭代器(iterators)、空间配置器(allocator)、配接器(adapters)、算法(algorithms)、仿函数(functors)六个部分,以下案例主要是在学习时对容器的总结笔记,基本上涵盖了关于容器之间,能够想到的任何操作,一次性全部涵盖其中。

String 字串操作容器

String字符串操作容器是C++标准中实现的一个重要容器,其主要用于对字符串的高效处理,它和C风格中的string.h并不是同一个库,两个库有极大的差距,C库中的string.h主要面向过程提供一些处理函数,而C++库中的string则是基于类实现的更高效的一种字符串处理方法集,类中提供了非常方便的成员函数供我们使用.

字符串构造函数: 因为字符串关键字其实是一个类,我们可以通过构造函数完成初始化字符串.

代码语言:javascript
复制
#include <iostream>
#include <string>
using namespace std;

int main(int argc, char* argv[])
{
	string str("hello lyshark"); // 定义一个字符串
	string str_1(str);           // 构造函数,将 str中的内容全部复制到str_1
	
	string str_2(str, 2, 5);     // 构造函数,从字符串str的第2个元素开始,复制5个元素,赋值给str_2
	
	string str_3(str.begin(), str.end()); // 复制字符串 str 的所有元素,并赋值给 str_3

	char ch[] = "lyshark";
	string str_4(ch, 3);    // 将字符串ch的前5个元素赋值给str_4

	string str_5(5, 'x');   // 将 5 个 'X' 组成的字符串 "XXXXX" 赋值给 str_5
	
	system("pause");
	return 0;
}

字符串对象赋值: 使用String对象中的assign()函数,可以实现字符串之间的赋值.

代码语言:javascript
复制
#include <iostream>
#include <string>
using namespace std;

int main(int argc, char* argv[])
{
	string str,new_str;

	str = "lyshark";     // 基本的对象赋值
	new_str.assign(str); // 把str中的数据赋值给new_str

	string s1, s2, s3;

	s1.assign(str, 1, 4);     // 字符串截取从str中第1位开始向后截取4个字符
	s2.assign(5, 'A');        // 想字符串中填充5个A

	cout << s3 << endl;
	
	system("pause");
	return 0;
}

字符串遍历操作: 通过使用str.size()函数获取到字符的具体个数,最后循环遍历输出这些字符串.

代码语言:javascript
复制
#include <iostream>
#include <string>
#include <stdexcept>
using namespace std;

int main(int argc, char* argv[])
{
	string str = "hello lyshark";

	// 第一种遍历如果字符串越界,会直接挂掉
	for (int x = 0; x < str.size(); x++)
		cout << str[x] << endl;

	// 第二种at遍历,如果越界会抛出异常
	try
	{
		for (int x = 0; x < str.size(); x++)
			cout << str[x] << endl;
	}
	catch (out_of_range &e)
	{
		cout << "异常类型: " << e.what() << endl;
	}
	system("pause");
	return 0;
}

字符串添加与删除: 使用append()添加字符串,使用insert()插入字符串,使用erase()删除指定范围字符串.

代码语言:javascript
复制
#include <iostream>
#include <string>
using namespace std;

int main(int argc, char* argv[])
{
	string str1("hello "), str2("lyshark");
	str1.append(str2);        // 将str2的内容追加到str1后面
	str1.append(str2, 1, 3);  // 将str2内容从第1个到第3个字符追加到str1后面
	str1.append(5, 'A');      // 向str1子串里面追加5个A

	string str3 = "this is ok";
	string str4 = str3.substr(1,3);  // 截取子串 => his
	string str5 = str3.substr(1, 5); // 截取子串 => his i

	string str6 = "real steel";
	str6.erase(5);               // 从第5个字符开始向后删除所有
	str6.erase(0, 4);            // 从第0个字符开始向后删除4个

	string str7 = "hello lyshark";
	str7.insert(2, "123");     // 在下标 2 处插入字符串"123"
	str7.insert(3, 4, 'A');    // 在下标 3 处插入 5 个 'A'
	
	system("pause");
	return 0;
}

字符串查找与替换: 使用find()可查找字符串第一次出现的位置,使用compare比较字符串,使用replace()替换字符串.

代码语言:javascript
复制
#include <iostream>
#include <string>
using namespace std;

int main(int argc, char* argv[])
{
	string str1("Source Code"),str2("Source Code");
	int x;

	if ((x = str1.find("u")) != string::npos)
		cout << str1.substr(x) << endl;    // 查找字符u第一次出现的位置

	if ((x = str1.find("Source", 3)) != string::npos)
		cout << str1.substr(x) << endl;    // 查找Source字符串,并从下标3位置输出
	
	if ((x = str1.find_first_of("urc")) != string::npos)
		cout << x << endl;                // 查找urc字符串最先出现的位置

	if (str1.compare(str2))               // 比较两个字符串是否相等
		cout << "False" << endl;

	string str3 = "hello lyshark";
	str3.replace(1, 3, "abcde");          // 从第1处开始替换3个字符
	cout << str3 << endl;
	
	system("pause");
	return 0;
}

字符串首尾数据提取: 我们可以通过find()查找指定通配符,然后使用substr()灵活的提取左面或右面的字符串.

代码语言:javascript
复制
#include <iostream>
#include <string>
using namespace std;

int main(int argc, char* argv[])
{
	string email = "admin@blib.cn";
	int pos = email.find("@");

	string username = email.substr(0, pos); // 提取出用户名
	cout << username << endl;

	string mail = email.substr(pos+1);      // 提取出mail邮箱
	cout << mail << endl;

	system("pause");
	return 0;
}

字符串与字符互转: 使用str.c_str()将string转换为char,使用string str()将char强转为string.

代码语言:javascript
复制
#include <iostream>
#include <string>
using namespace std;

int main(int argc, char* argv[])
{
	string str = "lyshark";

	// string 转换为 -> char *
	const char *ptr = str.c_str();
	cout << ptr << endl;

	// char * 转换为 -> string
	string str1(ptr);
	cout << str1 << endl;

	// int 转换为 -> string
	int Num = 546;
	string str2 = to_string(Num);
	cout << str2 << endl;
	
	system("pause");
	return 0;
}

字符串大小写互转: 使用topper()将小写字符变成大写,使用tolower()将大写字符变为小写.

代码语言:javascript
复制
#include <iostream>
#include <string>
using namespace std;

int main(int argc, char* argv[])
{
	string str = "lyshark";
	for (int x = 0; x < str.size(); x++)
		str[x] = toupper(str[x]);   // 全部变大写
		//str[x] = tolower(str[x]); // 全部变小写
		cout << str << endl;
	
	system("pause");
	return 0;
}

Vector 数组向量容器

Vector 容器是一种简单的高效率的数组容器,该容器可以方便、灵活地代替数组,容器可以实现动态对数组阔扩容删除等各种复杂操作,其时间复杂度O(l)常数阶,其他元素的插入和删除为O(n)线性阶,其中n为容器的元素个数,vector具有自动的内存管理机制,对于元素的插入和删除可动态调整所占用的内存空间.

数组向量的基本使用: 首先我们来实现遍历数组向量,向数组向量中放入元素与移出元素.

代码语言:javascript
复制
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

void MyPrint(vector<int>& var)
{
	cout << "empty = " << var.empty() << " --> size = " << var.size()  << endl;
	cout << "capacity = " << var.capacity() << " --> max_size = " << var.max_size() << endl;
	for_each(var.begin(), var.end(), [](int val){ cout << val << endl; });
	cout << "---------------------------------------------------------" << endl;
}

int main(int argc, char* argv[])
{
	vector<int> var{ 1, 2, 3 };

	var.push_back(4);  // 放入元素
	MyPrint(var);
	var.pop_back();    // 弹出一个元素
	MyPrint(var);
	var.resize(10);    // 重新设置最大存储
	var.reserve(30);   // 调整数据空间大小
	MyPrint(var);

	system("pause");
	return 0;
}

数组向量的正/反向遍历: 前两种遍历方式分别是通过下标法和迭代实现正向遍历,最后的第三种方式是实现的反向遍历.

代码语言:javascript
复制
#include <iostream>
#include <string>
#include <vector>
using namespace std;

int main(int argc, char* argv[])
{
	// 第一种遍历数组的方式,使用数组的下标实现遍历
	vector<string> str_array{ "admin", "guest", "lyshark" };
	cout << "str_array sizeof:" << str_array.capacity() << endl;
	for (int x = 0; x < str_array.size(); x++)
	{
		cout << "str_array --> " << str_array[x] << endl;
	}
	cout << endl;

	// 第二种遍历数组的方式,使用迭代器实现的正向遍历
	vector<int> int_array{ 1, 2, 3, 4, 5 };
	vector<int>::const_iterator item;
	int each = 0;
	for (item = int_array.begin(), each = 0; item != int_array.end(); ++item, ++each)
	{
		cout << "int_array[" << each << "] --> " << (*item) << endl;
	}
	cout << endl;

	// 第三种遍历数组的方式,使用迭代器实现的反向遍历
	vector<int> rint_array{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	vector<int>::reverse_iterator start, end; // 定义向量迭代器
	end = int_array.rend();
	for (start = int_array.rbegin(); start != end; start++)
	{
		cout << "int_array --> " << *start << endl;
	}

	system("pause");
	return 0;
}

数组向量的正/反向排序: 首先生成10个随机数,然后分别对这些数字进行正向排序,与反向排序.

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 实现的一个排序回调函数,反向排序需要使用该回调
bool MyCompare(int value1, int value2){ return value1 > value2; }

int main(int argc, char* argv[])
{
	vector<int> *int_array = new vector<int>;

	// 生成10个随机数用于测试
	for (int x = 0; x < 10; x++)
		int_array->push_back(rand() % 100);

	// 遍历的方式实现 正向排序
	std::sort(int_array->begin(), int_array->end());
	vector<int>::const_iterator item = int_array->cbegin();
	while (item != int_array->cend())
	{
		cout << (*item) << " ";
		item++;
	}
	cout << endl;

	// 遍历的方式实现 反向排序
	std::sort(int_array->begin(), int_array->end(), MyCompare);
	vector<int>::const_iterator item_1 = int_array->cbegin();
	while (item_1 != int_array->cend())
	{
		cout << (*item_1) << " ";
		item_1++;
	}

	system("pause");
	return 0;
}

向数组向量中插入元素: 向数组中插入元素可以使用push_back()方法,当需要插入到指定位置时可使用insert()方法.

代码语言:javascript
复制
#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main(int argc, char* argv[])
{
	// 定义数组容器,并赋予初始值
	vector<string> str_array{ "admin", "guest", "lyshark" };

	str_array.push_back("django");     // 插入元素
	str_array.push_back("python");     // 插入元素
	str_array.pop_back()               // 弹出元素
	// cout << str_array[3] << endl;                   // 通过元素下标遍历数据
	str_array.insert(str_array.begin() + 2, "ruby");   // 在数组索引2的位置插入元素
	str_array.insert(str_array.end(), "C++");          // 在数组最后插入元素

	for (int x = 0; x < str_array.size(); x++)
		cout << "str_array[" << x << "] --->" << str_array[x] << endl;

	system("pause");
	return 0;
}

向数组向量中插入结构指针: 首先我们定义一个数组向量,然后向指定的数组中插入结构的首地址.

代码语言:javascript
复制
#include <iostream>
#include <vector>

using namespace std;

typedef struct
{
	int ID;
	char szName[20];
}Person, *Ptr;

int main(int argc, char* argv[])
{
	vector<Person> ary[10];

	Person p1 = { 1, "admin" };
	Person p2 = { 2, "lyshark" };
	Person p3 = { 3, "guest" };

	ary[0].push_back(p1);
	ary[1].push_back(p2);
	ary[2].push_back(p3);

	for (int x = 0; x < 3; x++)
	{
		vector<Person>::iterator item = ary[x].begin();
		cout << "ID: " << (*item).ID <<" ---> Name: " << (*item).szName << endl;
	}
	system("pause");
	return 0;
}

向数组向量中插入类指针: 此处插入类指针与上方的结构指针是类似的,此处不在说明了.

代码语言:javascript
复制
#include <iostream>
#include <vector>

using namespace std;

class MyAnimal{
public:
	char *name;
	int id;
public:
	MyAnimal(char* name, int id)
	{
		this->name = name;
		this->id = id;
	}
};

int main(int argc, char* argv[])
{
	MyAnimal* pDog = new MyAnimal("dog", 1);
	MyAnimal* pMonkey = new MyAnimal("monkey", 2);
	MyAnimal* pSnake = new MyAnimal("psnake", 3);

	vector<MyAnimal *> var;     // 定义模板
	var.push_back(pDog);        // 将指针放入列表
	var.push_back(pMonkey);
	var.push_back(pSnake);
	// 指针列表的遍历器
	vector<MyAnimal*>::iterator start, end;
	end = var.end();
	for (start = var.begin(); start != end; start++)
	{
		cout <<"ID: "<<(*start)->id << " ---> " << "Name: " << (*start)->name << endl;
	}
	system("pause");
	return 0;
}

在数组容器中嵌套容器: 首先声明var容器,该容器的内部定义为容器类型,然后初始化v1,v2,将其放入var容器中.

代码语言:javascript
复制
#include <iostream>
#include <vector>
using namespace std;

int main(int argc, char* argv[])
{
	// 容器中内嵌容器
	vector< vector<int> > var;
	vector<int> v1;
	vector<int> v2;

	for (int x = 0; x < 5; x++)
	{ // 放入小容器中的数据
		v1.push_back(x);
		v2.push_back(x + 10);
	}
	// 将小容器放入大容器中
	var.push_back(v1);
	var.push_back(v2);
	
	// 遍历所有容器中的数据, 由于是嵌套容器,所以我们要先来遍历第一层,在第一层中遍历第二层.
	for (vector<vector<int>>::iterator item = var.begin(); item != var.end(); item++)
	{
		for (vector<int>::iterator vitem = (*item).begin(); vitem != (*item).end(); vitem++)
		{
			cout << (*vitem) << " ";
		}
		cout << endl;
	}
	system("pause");
	return 0;
}

函数参数定义为容器类型: 这里我们定义了函数MyPrintVector()其形参可接受vector<int>类型的容器.

代码语言:javascript
复制
#include <iostream>
#include <vector>
using namespace std;


void MyPrintVector(vector<int> &var)
{
	for (vector<int>::iterator item = var.begin(); item != var.end(); item++)
	{
		cout << (*item) << " ";
	}
	cout << endl;
}

int main(int argc, char* argv[])
{
	vector <int> var;
	int arry[] = { 1, 2, 3, 4, 5 };

	// 两种不同的容器构造方式
	vector<int> v1 (arry, arry + sizeof(arry) / sizeof(int));
	vector<int> v2(v1.begin(), v1.end());

	MyPrintVector(v2);       // 打印v2容器中的内容

	vector<int> v3(10, 20);  // 生成容器,里面包含10个20
	MyPrintVector(v3);

	vector<int> v4;          // 赋值的使用,里面包含10个20
	v4.assign(v3.begin(), v3.end());
	MyPrintVector(v4);

	v4.swap(v2);             // v2与v4容器内容互换
	MyPrintVector(v4);

	system("pause");
	return 0;
}

数组向量元素的删除: 数组向量并没有直接删除元素的方法,需要使用find()方法找到元素,迭代并使用erase()删除元素.

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main(int argc, char* argv[])
{
	vector<int> int_array {1,2,3,4,5,6,7,8,9,10};

	// find 找到元素7并删除
	vector<int>::iterator item = find(int_array.begin(), int_array.end(), 7);
	if (item != int_array.cend())
		int_array.erase(item);  // 删除指定元素

	// 删除后对数组进行遍历
	vector<int>::iterator start, end;
	end = int_array.end();
	for (start = int_array.begin(); start != end; start++)
	{
		cout << (*start) << endl;
	}
	system("pause");
	return 0;
}

Deque 双向队列容器

Deque双向队列容器与Vector非常相似,它不但可以在数组尾部插入和删除元素,还可以在头部进行插入和删除,队列算法的时间复杂度也是常数阶O(1),队列内部的数据机制和性能与Vector不同,一般来说当考虑到容器元素的内存分配策略和操作的性能时,Deque相对于Vector较有优势.

单向队列的基本操作: 单向队列容器遵循先进先出FIFO的原则,最先从队列尾部插入的容器会最先被弹出队列.

代码语言:javascript
复制
#include <iostream>
#include <queue>
using namespace std;

int main(int argc, char* argv[])
{
	queue<int> que;

	que.push(1); // 入队列
	que.push(2);

	while (!que.empty())
	{
		cout << "Head: " << que.front() << endl; // 队头
		cout << "End: " << que.back() << endl;   // 队尾
		que.pop(); // 出队列
	}
	cout << "Size: " << que.size() << endl;
	system("pause");
	return 0;
}

双向队列的基本操作: 双向队列相比于单项来说,它的前面后面都可以插入和取出数据,但同样遵循FIFO原则.

代码语言:javascript
复制
#include <iostream>
#include <deque>

using namespace std;

int main(int argc, char* argv[])
{
	deque<int> deq{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

	deq.push_back(11);  // 向队尾放入元素
	deq.push_front(12); // 向队头放入元素

	deq.pop_back();     // 从队尾弹出一个元素
	deq.pop_front();    // 从队头弹出一个元素

	cout << "是否为空: " << deq.empty() << endl;
	cout << "首个元素: " << deq.front() << endl;
	cout << "末尾元素: " << deq.back() << endl;
	cout << "元素个数: " << deq.size() << endl;
	cout << "最大元素数: " << deq.max_size() << endl;

	system("pause");
	return 0;
}

双向队列正/反向遍历: 通过使用下标法和迭代器都可以实现对队列的数据遍历,这里先演示正向遍历,然后反向遍历.

代码语言:javascript
复制
#include <iostream>
#include <deque>

using namespace std;

int main(int argc, char* argv[])
{
	deque<int> deq{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

	// 双向队列的正向遍历: 此处有两种遍历方法
	for (int x = 0; x < deq.size(); x++)    // 第一种,通过下标遍历数据
		cout << deq[x] << " " ;
	cout << endl;

	deque<int>::iterator start, end;        // 第二种,通过迭代器遍历数据
	end = deq.end();
	for (start = deq.begin(); start != end; start++)
		cout << (*start) << " " ;
	cout << endl;

	// 双向队列的反向遍历: 此处我们使用迭代器遍历
	deque<int>::reverse_iterator rstart, rend;
	rend = deq.rend();
	for (rstart = deq.rbegin(); rstart != rend; rstart++)
	{
		cout << (*rstart) << " " ;
	}

	system("pause");
	return 0;
}

双向队列插入/弹出元素: 通过使用insert()向队列中插入元素,使用erase()可以弹出指定位置的元素.

代码语言:javascript
复制
#include <iostream>
#include <deque>

using namespace std;

int main(int argc, char* argv[])
{
	deque<int> deq{ 1, 2, 3, 4, 5 };

	deq.push_back(6);               // 从队列末尾追加元素
	deq.push_front(0);              // 从队列首部追加元素
	deq.insert(deq.begin() + 1, 9); // 在第二个元素前插入9

	deq.pop_front();                // 从队列首部弹出元素
	deq.pop_back();                 // 从队列尾部弹出元素
	deq.erase(deq.begin() + 1);     // 弹出第二个(下标索引)元素


	for (int x = 0; x < deq.size(); x++)
		cout << deq[x] << " ";
	cout << endl;

	system("pause");
	return 0;
}

函数参数传递双向队列: 将我们定义的deque<int> deq的指针传递给PrintDeque这个函数进行迭代遍历.

代码语言:javascript
复制
#include <iostream>
#include <deque>
#include <algorithm>
using namespace std;

// 定义只读deque双端队列
void PrintDeque(const deque<int> &deq)
{
	for (deque<int>::const_iterator item = deq.begin(); item != deq.end(); item++)
	{
		// 迭代器类型: iterator=>普通迭代器 reverse_iterator=>逆序迭代器 const_iterator=>只读迭代器
		cout << (*item) << endl;
	}
}

int main(int argc, char* argv[])
{
	deque<int> deq = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	PrintDeque(deq);
	system("pause");
	return 0;
}

List/Slist 动态链表容器

List双向链表是一种序列容器,它的数据元素可以通过链表指针串接成逻辑意义上的线性表,不同于采用线性表顺序存储结构的Vector和Deque容器,双向链表中任一位置的元素,查找,插入和删除,都具有高效的常数阶算法时间复杂度O(1).

List的缺点是无法通过位置来直接访问序列中的元素,也就是说,不能动态跨段索引元素.为了访问 list 内部的一个元素,必须一个一个地遍历元素,通常从第一个元素或最后一个元素开始遍历.

双向链表遍历整数: 首先动态生成一个链表,里面存储1-10之间的数,然后通过链表指针开始遍历这个数值链表.

代码语言:javascript
复制
#include <iostream>
#include <list>
using namespace std;

int main(int argc, char* argv[])
{
	list<int> MyList;
	// 生成10个测试数据,并链入链表中.
	for (int x = 0; x < 10; x++)
		MyList.push_back(x);

	// 将node节点初始化为第一个节点的下一个节点,第一个节点是链表头,无数据.
	list<int>::_Nodeptr node = MyList._Myhead->_Next;

	for (int x = 0; x < MyList._Mysize; x++)
	{
		cout << "Node: " << node->_Myval << endl;
		node = node->_Next;         // 每次输出,将node指向下一个链表
		if (node == MyList._Myhead) // 如果到头了,直接指向头结点的第二个节点
		{
			node = node->_Next;     // 由于是双向链表,所以到头了会回到起始位置
		}                               // 此时我们执行 node->_Next 继续指向开头
	}
	system("pause");
	return 0;
}

双向链表遍历结构体: 上方遍历的是一个整数链表,接下来实现的是遍历Student这个结构体中的所有数据.

代码语言:javascript
复制
#include <iostream>
#include <list>
using namespace std;

struct Student{
	char * name;
	int age;
	char * city;
};

bool MyCompare(Student &s1, Student &s2)
{   // 实现从大到小排序
	if (s1.age > s2.age)
		return true;
	return false;
}

int main(int argc, char* argv[])
{
	Student stu[] = {
		{ "admin", 22, "beijing" },
		{ "lisi", 32, "shanghai" },
		{ "wangwu", 26, "shandong" },
		{"wangermazi",8,"jinan"}
	};

	list<Student> MyList;
	MyList.push_back(stu[0]);  // 装入链表数据
	MyList.push_back(stu[1]);
	MyList.push_back(stu[2]);
	MyList.push_back(stu[3]);

	// 根据Student结构中的age从大到小排序
	MyList.sort(MyCompare);

	// 遍历链表
	list<Student>::iterator start, end;
	for (start = MyList.begin(); start != MyList.end(); start++)
	{
		cout << (*start).name << " ";
		cout << (*start).age << " ";
		cout << (*start).city << endl;
	}
	system("pause");
	return 0;
}

实现正反向遍历链表: 链表容器不支持随机访问只能遍历,使用begin()/end()正向遍历,使用rbegin()/rend()反向遍历.

代码语言:javascript
复制
#include <iostream>
#include <list>
using namespace std;

int main(int argc, char* argv[])
{
	list<int> MyList{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	// 正向打印链表元素
	for (list<int>::iterator item = MyList.begin(); item != MyList.end(); item++)
		cout << *item << endl;
	// 反向打印链表元素
	for (list<int>::reverse_iterator item = MyList.rbegin(); item != MyList.rend(); item++)
		cout << *item << endl;
	system("pause");
	return 0;
}

遍历链表中指定元素: 通过使用结构体存储人物数据,然后使用迭代器查找id=3的人物结构,找到后输出它的Name属性.

代码语言:javascript
复制
#include <iostream>
#include <list>
#include <string>
using namespace std;

struct Student{
	int id;
	string name;
};

int main(int argc, char* argv[])
{
	list<Student> MyList;
	// 定义列表中的元素集合
	Student stu[] = {
		{ 1,"aaddm"},
		{ 2,"admin"},
		{ 3,"waann" },
		{ 4,"ruiii" }
	};

	for (int x = 0; x < 4; x++)
	{ // 循环插入测试结构 stu[0] - stu[4]
		MyList.push_back(stu[x]);
	}

	// 遍历链表中ID=3的元素
	list<Student>::iterator start, end;
	for (start = MyList.begin(); start != MyList.end(); start++)
	{
		if ((*start).id == 3) // 寻找ID是3的结构体,找到后输出其name属性
		{
			cout << "UName: " << (*start).name << endl;
		}
	}
	system("pause");
	return 0;
}

实现插入/删除链表元素: 定义list<int>链表,通过insert()向链表中插入元素,通过remove()移除指定的元素.

代码语言:javascript
复制
#include <iostream>
#include <list>
using namespace std;

void MyPrint(list<int> &MyList)
{
	list<int>::iterator start, end;
	for (start = MyList.begin(); start != MyList.end(); start++)
		cout << *start << " ";
	cout << endl;
}

int main(int argc, char* argv[])
{
	list<int> MyList{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	MyList.push_back(10);  // 尾部插入数据
	MyList.push_front(0);  // 头部插入数据

	MyList.pop_front();    // 头删数据
	MyList.pop_back();     // 尾删除数据

	MyList.insert(MyList.begin(), 500); // 从开头插入500
	MyList.insert(MyList.end(), 1000);  // 从结尾插入1000

	MyList.remove(7);    // 移除7这个元素
	MyPrint(MyList);
	system("pause");
	return 0;
}

实现整数链表正反向排序: 定义list<int>链表,并通过sort()实现正反向排序,通过reverse()实现链表翻转.

代码语言:javascript
复制
#include <iostream>
#include <list>
using namespace std;

void MyPrint(list<int> &MyList)
{
	list<int>::iterator start, end;
	for (start = MyList.begin(); start != MyList.end(); start++)
		cout << *start << " ";
	cout << endl;
}

// 实现的从大到小排序的回调函数
bool MyCompare(int value1, int value2) { return value1 > value2; }

int main(int argc, char* argv[])
{
	list<int> MyList{ 12,56,33,78,9,43,2,1,7,89 };

	MyList.reverse();        // 对链表进行翻转
	MyPrint(MyList);

	MyList.sort();           // 从小到大排序
	MyPrint(MyList);

	MyList.sort(MyCompare);  // 从大到小排序
	MyPrint(MyList);

	system("pause");
	return 0;
}

实现类链表正反向排序: 定义Person类存储数据,使用sort()函数设置自定义回调函数MyCompare()实现对类中数据排序.

代码语言:javascript
复制
#include <iostream>
#include <list>
#include <string>
using namespace std;

class Person
{
public:
	string m_name;
	int m_age;
	int m_height;

public: Person(string name, int age, int height){
		this->m_name = name;
		this->m_age = age;
		this->m_height = height;
	}
};
// 排序规则为: 如果年龄相同,则按照身高由低到高排列
bool MyCompare(Person &x,Person &y)
{
	if (x.m_age == y.m_age)
		return x.m_height < y.m_height; // 身高升序排列
	else
		return x.m_age > y.m_age;       // 年龄降序排列
}

int main(int argc, char* argv[])
{
	list<Person> MyList;

	Person p1("a", 20, 169);  // 定义元素数据
	Person p2("b", 14, 155);
	Person p3("c", 14, 165);

	MyList.push_back(p1);     // 加到链表里
	MyList.push_back(p2);
	MyList.push_back(p3);

	MyList.sort(MyCompare);  // 排序代码

	// 排序后进行打印
	for (list<Person>::iterator it = MyList.begin(); it != MyList.end(); it++)
		cout << "Name: " << it->m_name << " Age: " << it->m_age << " Height: " << it->m_height << endl;
	system("pause");
	return 0;
}

实现类链表成员的删除: 自定义Person结构来存储人物的信息,然后重载等于号,实现让remove可以删除Person中的数据.

代码语言:javascript
复制
#include <iostream>
#include <list>
#include <string>
using namespace std;

class Person
{
public:
	string m_name;
	int m_age;
	int m_height;

public: Person(string name, int age, int height){
		this->m_name = name;
		this->m_age = age;
		this->m_height = height;
}
// 重载等于号 == 让 remove() 函数,可以删除自定义的Person类型的结构
public: bool operator==(const Person &p) {
		if (this->m_name == p.m_name && this->m_age == p.m_age && this->m_height == p.m_height)
			return true;
		return false;
	}
};

int main(int argc, char* argv[])
{
	list<Person> MyList;

	Person p1("a", 20, 169);
	Person p2("b", 14, 155);
	Person p3("c", 34, 165); // 初始化并给Person赋值

	MyList.push_back(p1);    // 将参数放入链表中
	MyList.push_back(p2);
	MyList.push_back(p3);

	MyList.remove(p3);   // 删除这个类中的p3成员

	// 删除p3数据后,通过使用迭代器遍历这个链表,查看情况.
	for (list<Person>::iterator it = MyList.begin(); it != MyList.end(); it++)
		cout << "Name: " << it->m_name << " Age: " << it->m_age << " Height: " << it->m_height << endl;
	system("pause");
	return 0;
}

Set/Multiset 集合容器

Set集合使用的是红黑树的平衡二叉检索树的数据结构,来组织泛化的元素数据,通常来说红黑树根节点每次只能衍生出两个子节点,左面的节点是小于根节点的数据集合,右面的节点是大于根节点的集合,通过这样的方式将数据组织成一颗看似像树一样的结构,而平衡一词的含义则是两边的子节点数量必须在小于等1的区间以内.

需要注意的是,Set集合天生去重,所有元素都会根据元素的键值自动的排序,并且Set元素在确定后无法进行更改,换句话说Set的Iterator是一种Const_iterator,而Multiset则允许出现重复的数据,如需使用只需要将set<int>改为multiset<int>即可,Multiset操作方式与API函数与Set集合保持相同.

正反向遍历集合元素: 通过迭代器实现对集合容器的正反向遍历,注意Set集合只能使用insert方法向集合插值.

代码语言:javascript
复制
#include <iostream>
#include <set>
using namespace std;

void PrintSet(set<int>& s ,int flag)
{
	if (flag == 1)
	{ // 正向遍历元素
		for (set<int>::iterator it = s.begin(); it != s.end(); it++)
			cout << (*it) << " ";
	}
	else if (flag == 0)
	{ // 反向遍历元素
		for (set<int>::reverse_iterator it = s.rbegin(); it != s.rend(); it++)
			cout << (*it) << " ";
	}
}

int main(int argc, char* argv[])
{
	set<int> var { };

	var.insert(56);
	var.insert(67);  // 插入元素
	var.insert(99);
	PrintSet(var,0); // 打印并从大到小排列

	if (var.empty()) // 判断是否为空
		cout << "None" << endl;
	else
		cout << "size: " << var.size() << endl;

	var.erase(var.begin());   // 删除第一个元素
	var.erase(99);            // 删除99这个元素
	PrintSet(var, 0);         // 打印并从大到小排列
	system("pause");
	return 0;
}

查找集合中指定元素: 通过find可实现查找集合指定元素,lower/upper/equal bound则实现对元素区间的遍历.

代码语言:javascript
复制
#include <iostream>
#include <set>
using namespace std;

int main(int argc, char* argv[])
{
	set<int> var { 23,44,56,78,90,0,90,12,54,67,85,3,4,7};

	// 寻找set集合中数值是90的
	set<int>::iterator pos = var.find(90);
	if (pos != var.end())  // 寻找90是否存在
		cout << "找到了: " << *pos << endl;
	
	// count(key) 查找90存在几个,对于set而言返回结果是 1或者0
	int number = var.count(90);
	cout << "90是否存在: " << number << endl;

	// lower_bound(keyElem); 返回第一个 key>=keyElem 元素的迭代器
	set<int>::iterator it = var.lower_bound(4); // 寻找4是否存在
	if (it != var.end())
		cout << "找到了 lower_bound(4) 的值:" << *it << endl;

	// upper_bound(keyElem); 返回第一个 key>keyElem 元素的迭代器
	set<int>::iterator it2 = var.upper_bound(4); // 寻找4相邻值
	if (it2 != var.end())
		cout << "找到了 upper_bound(4) 的值:" << *it2 << endl;

	// equal_range(keyElem) 返回容器中key与keyElem相等的上下限的两个迭代器.
	// 下限就是 lower_bound 上限就是 upper_bound 需要分别迭代输出
	pair<set<int>::iterator, set<int>::iterator> ret = var.equal_range(4);
	if (ret.first != var.end())
		cout << "找到 lower_bound(4): " << *(ret.first) << endl;
	if (ret.second != var.end())
		cout << "找到 upper_bound(4): " << *(ret.second) << endl;

	system("pause");
	return 0;
}

设置默认集合排序方式: 集合默认情况下会从小到大的将数据排列整齐,我们可以自定义仿函数让其从大到小排序.

代码语言:javascript
复制
#include <iostream>
#include <set>
#include <string>
using namespace std;

class MyCompare
{ // 通过仿函数,重载小括号,实现默认从大到小排列
public: bool operator()(int v1, int v2) {
		return v1 > v2;    // 从大到小
		// return v1 < v2; 从小到大
	}
};

int main(int argc, char* argv[])
{
	set<int, MyCompare> var;

	var.insert(6);
	var.insert(3);
	var.insert(9);

	for (set<int, MyCompare>::iterator it = var.begin(); it != var.end(); it++)
		cout << *it << endl;

	system("pause");
	return 0;
}

向集合插入自定义类型: 此处使用类做数据存储,插入自定义数据类型时,必须在一开始就指定好排序规则,否则会报错.

代码语言:javascript
复制
#include <iostream>
#include <set>
#include <string>
using namespace std;

class Person {
public:
	string m_name;
	int m_age;

public: Person(string name, int age) {
	this->m_name = name;
	this->m_age = age;
	}
};

class MyCompare{
	// 通过仿函数,重载,实现默认降序排列
public: bool operator()(const Person & p1, const Person & p2){
		if (p1.m_age > p2.m_age) // 指定为降序排列
			return true;
		return false;
	}
};

int main(int argc, char* argv[])
{
	set<Person,MyCompare> var;

	Person p1("dawa", 22);   // 初始化
	Person p2("xiwa", 44);
	var.insert(p1);          // 插入自定义数据类型
	var.insert(p2);

	// 显示出自定义类型
	for (set<Person, MyCompare>::iterator it = var.begin(); it != var.end();it ++)
	{
		cout << "Name: " << (*it).m_name << "Age: " << (*it).m_age << endl;
	}
	system("pause");
	return 0;
}

Map/Multimap 序列容器

Map映射容器属于关联容器,它的每个键对应着每个值,容器的数据结构同样采用红黑树进行管理,插入的键不允许重复,但值是可以重复的,如果使用Multimap声明映射容器,则同样可以插入相同的键值.

Map中的所有元素都会根据元素的键值自动排序,所有的元素都是一个Pair同时拥有实值和键值,Pair的第一个元素被视为键值,第二个元素则被视为实值,Map 容器中不允许两个元素有相同的键出现.

通过对组实现键值对: 对组pair<>是一个键值对的组合,类似于一个字典,每个对组中,包含1个key和1个value.

代码语言:javascript
复制
#include <iostream>
#include <set>
#include <string>
using namespace std;

int main(int argc, char* argv[])
{   // 创建的对组字符串
	pair<string, int> p(string("lyshark"), 100);
	pair<string, int> p2 = make_pair("jerry", 200);
	cout << "Name: " << p.first << endl;
	cout << "Age: " << p.second << endl;

	// 检测集合元素是存在重复的,如果出现重复的则报错
	set<int> var;
	var.insert(10);  // 由于插入过10这个元素,所以在此插入则会报错
	pair<set<int>::iterator, bool> ret = var.insert(10);
	if (!ret.second)
		cout << "insert error" << endl;

	system("pause");
	return 0;
}

正反向遍历映射容器: 通过使用begin/rbegin,end/rend等迭代器,实现对MAP映射容器元素的正反向遍历.

代码语言:javascript
复制
#include <iostream>
#include <map>
#include <string>
using namespace std;

int main(int argc, char* argv[])
{
	map<string, int> mp;
	// 三种方式实现map容器插入操作
	mp.insert(pair<string, int>("admin0", 100));
	mp.insert(make_pair("admin1", 200));
	mp["admin2"] = 300;

	mp.erase("admin2");    // 删除第3个数据

	// 正向遍历键值对
	for (map<string, int>::iterator it = mp.begin(); it != mp.end(); it++)
		cout << "key = " << it->first << " --> value = " << it->second << endl;

	cout << endl;
	// 反向遍历键值对
	for (map<string, int>::reverse_iterator it = mp.rbegin(); it != mp.rend();it ++)
		cout << "key = " << it->first << " --> value = " << it->second << endl;
	system("pause");
	return 0;
}

查找映射容器中的元素: 首先创建一个映射容器,然后通过迭代器mp.find("admin0");遍历查找特定的映射元素.

代码语言:javascript
复制
#include <iostream>
#include <map>
#include <string>
using namespace std;

int main(int argc, char* argv[])
{
	map<string, int> mp;

	mp["admin0"] = 100;
	mp["admin1"] = 200;
	mp["admin2"] = 300;
	
	// 寻找admin0是否存在于键值对中
	map<string, int>::iterator pos = mp.find("admin0");
	if (pos != mp.end())
		cout << "key = " << pos->first << " --> value = " << pos->second << endl;

	// lower_bound(keyElem) 返回第一个key=keyElem元素的迭代器
	map<string, int>::iterator ret = mp.lower_bound("admin0");
	if (ret != mp.end())
		cout << "lower_bound key = " << ret->first << " --> lower_bound value = " << ret->second << endl;
	
	// upper_bound(keyElem) 返回第一个key>keyElem元素的迭代器
	map<string, int>::iterator ret1 = mp.upper_bound("admin0");
	cout << "upper_bound key = " << ret1->first << " --> upper_bound value = " << ret1->second << endl;
	system("pause");
	return 0;
}

遍历映射容器中的结构: 上方代码是查找一个映射元素,本案例将查找一个映射结构,找到后打印出该结构的详细数据.

代码语言:javascript
复制
#include <iostream>
#include <map>
#include <string>
using namespace std;

struct StudentInfo{
	char *name;
	int year;
	char *addr;
};

struct StudentRecord{
	int id;
	StudentInfo stu;
};

int main(int argc, char* argv[])
{
	StudentRecord szArray[] = {
		{ 1, "admin0", 22, "beijing" },
		{ 2, "admin1", 33, "shanghai" },
		{ 3, "admin2", 24, "jinan" },
	};
	// 创建Map映射
	map<int, StudentInfo> mp;

	// 初始化,将学生数组装入映射
	for (int x = 0; x < 3; x++)
	{
		mp[szArray[x].id] = szArray[x].stu;
	}
	// 迭代遍历Map中所有的数据
	map<int, StudentInfo>::iterator start, end;
	end = mp.end();
	for (start = mp.begin(); start != end; start++)
		cout << "ID: " << (*start).first << " --> Name: " << (*start).second.name << endl;

	// 迭代寻找mp.find(1) 元素,并打印出其内部成员
	map<int, StudentInfo>::iterator i = mp.find(1);
	cout << "First: " << (*i).first << endl;
	cout << "Name: " << (*i).second.name << endl;
	system("pause");
	return 0;
}

通过映射容器实现分组: 定义三个不同的部门,然后通过映射容器对其进行分组,并实现遍历并打印出每个分组.

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <string>
#include <map>
using namespace std;

enum {RENLI,YANFA,MEISHU};  // 定义三个部门 RENLI=0
class Worker
{
public:
	string m_name;
	int m_money;
};
// 随机生成5个员工成员
void CreateWorker(vector<Worker> &v)
{
	string nameSeed = "ABCDE";
	Worker w;
	for (int x = 0; x < 5; x++)
	{
		string name;
		name += nameSeed[x];
		int money = rand() % 10000+10000;
		w.m_name = name;
		w.m_money = money;
		v.push_back(w);
	}
}
// 打印出指定的部门信息,查其他分组只需修改RENLI为其他即可
void ShowGroup(multimap<int, Worker> &m)
{
	cout << "Group:" << endl;
	multimap<int,Worker>::iterator pos = m.find(RENLI);
	int index = 0;            // 计数器每次递增,直到等于num
	int num = m.count(RENLI); // 人力部门有多少调数据
	for (; pos != m.end(), index < num; pos++, index++)
	{
		cout << "Name: " << pos->second.m_name << endl;
	}
}
// 实现员工分组
void SetGroup(vector<Worker> &v,multimap<int,Worker> & m)
{
	for (vector<Worker>::iterator it = v.begin(); it != v.end(); it++)
	{
		// 随机的产生一个部门编号
		int departmentId = rand() % 3;
		// 将员工分到multimap容器中, 1=mp
		m.insert(make_pair(departmentId, *(it)));
	}
}
int main(int argc, char* argv[])
{
	vector<Worker> v;
	CreateWorker(v);
	// 实现员工分组,分组的multimap容器
	multimap<int, Worker> mp;
	SetGroup(v,mp);   	// 实现员工分组
	ShowGroup(mp);      // 显示分组信息

	system("pause");
	return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-09-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • String 字串操作容器
  • Vector 数组向量容器
  • Deque 双向队列容器
  • List/Slist 动态链表容器
  • Set/Multiset 集合容器
  • Map/Multimap 序列容器
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档