STL常用容器_1

news2024/11/24 21:03:56

目录

一、string容器

1、基本概念

2、构造函数

3、赋值操作

4、字符串拼接

5、查找和替换

6、字符串比较

7、字符存取

8、插入与删除

9、获取字串

二、vector容器

1、基本概念

2、构造函数

3、赋值操作

4、容量和大小

5、插入和删除

6、数据存取

7、互换容器

8、预留空间

三、deque容器

1、基本概念

2、构造函数

3、赋值操作

4、容量和大小

5、插入与删除

6、数据存取

7、排序

四、案例:评委打分

1、案例说明:

有5名选手:ABCDE,10个评委分别对每一位选手打分,分数从60-100之间,去除最高分和最低分,取出每位选手的平均分

2、实现步骤:


一、string容器

1、基本概念

本质:

string是C++风格的字符串,但其本质是一个

对比:

C语言中,字符串是char*,但本质是一个指针

string是一个类,其内部封装了char*,管理这个字符串,但容器本身也是char*类型

特点:

string类内封装了很多成员方法,如:find、copy、delete、replace、insert

string管理char*所分配的内存,不用担心复制越界和取值越界等问题,由类内部进行负责


2、构造函数

/*
 string ();创建一个空的字符串
 string(const char* c);使用字符串c初始化
 string(const string&str);使用一个string对象初始化另一个string对象
 string(int n,char c);使用n个字符c初始化
*/
void test01()
{
	// 
	string s1;// 创建一个空的字符串

	const char* str = "Type here";
	string s2(str); // 把c的string转换成c++的string
	cout << s2 << endl;
	string s3(s2);	// ,使用一个string对象初始化另一个string对象
	cout << s3 << endl;
	string s4(88, 'x');// 使用n个字符x初始化s4
	cout << s4 << endl;
}

3、赋值操作

作用:将字符或字符串赋值给字符串

函数:

/*字符串赋值
 string& operator=(const char* s);    1 把char*类型字符串 赋值给 当前字符串
 string& operator=(const string& s);  2 把字符串s 赋值给 当前字符串
 string& operator=(char c);		      3 把字符c 赋值给 当前字符串
 string& assign(const	char* s);	  4 把字符串s 赋值给 当前字符串
 string& assign(const char* s,int n); 5 把字符串s前n个字符 赋值给 当前字符串
 string& assign(const string& s,int n);5 除去字符串s前n个字符 剩下的赋值给 当前字符串
 string& assign(const string& s);	  6 把字符串s 赋值给 当前字符串
 string& assign(int n,char c);		  7 把n个字符c 赋值给 当前字符串
*/

使用:无非就是前面用=号,后面用.assign()函数

void test02()
{
	const char* str0 = "Type there";
	string str1;
	str1 = str0;		// 1 
	str1 = "Type here"; // 1
	cout << str1 << endl;
	
	string str2;
	str2 = str1;		// 2
	cout << str2 << endl;

	string str3;
	str3 = 'x';			// 3
	cout << str3 << endl;

	string str4;
	str4.assign(str0);	// 4
	cout << str4 << endl;

	string str5;
	str5.assign(str0,4);// 5 传入const char*,前面4个
	cout << str5 << endl;
	str5.assign(str1, 4);// 5 传入string& s,除去前面4个剩下的
	cout << str5 << endl;

	string str6;
	str6.assign(str1);	// 6
	cout << str6 << endl;

	string str7;
	str7.assign(88, 'c');// 7
	cout << str7 << endl;
}

不过有趣的是,在第5个// string& assign(const char* s,int n); 时,如果传入const char* s,输出的将是前字符串前n个;如果传入的是const string& s,输出的是除去前n个所剩下的
 


4、字符串拼接

作用:将字符或字符串拼接到字符串后

函数:

/*字符串拼接
 string& operator+=(const char* s);	    1 把char*类型字符串 拼接到当前字符串末尾
 string& operator+=(const string& s);	2 把字符串s 拼接到当前字符串末尾
 string& operator+=(const char c);   	3 把字符c 拼接到当前字符串末尾
 string& append(const	char* s);		4 把字符串s 拼接到当前字符串末尾
 string& append(const char* s,int n);   5 把字符串s前n个字符 拼接到当前字符串末尾
 string& append(const string& s,int n); 5 把字符串s除去前n个字符 剩下的拼接到当前字符串末尾
 string& append(const string& s);		6 把字符串s 拼接到当前字符串末尾
 string& append(const string& s,int pos,int n);7 把字符串s从pos开始位置的n个字符 拼接到当前字符串末尾
*/

前面就是+=号重载,后面用append()函数

void test03()
{
	string str1 = "I";
	const char* s = " am ";
	//str1 += " am ";			// 1
	str1 += s;					// 1
	cout << str1 << endl;

	string str2 = "studious";
	str1 += str2;				// 2
	cout << str1 << endl;

	str1 += 'o';
	cout << str1 << endl;		// 3

	const char* s1 = " are ";
	string str3 = "You";
	str3.append(s1);		// 4
	cout << str3 << endl;

	str3.append(s1, 3);		// 5 把s1前3个字符追加到后面
	cout << str3 << endl;
	str3.append(str1, 3);	// 5 把str1除去前3个字符,剩下的追加到后面
	cout << str3 << endl;	

	str3.append(str1);
	cout << str3 << endl;	// 6

	string str4;
	str4.append(str3, 11, 14);//7
	cout << str4 << endl;
}

 同样的,在第5个// string& append(const char* s,int n); 时,如果传入const char* s,加在后面的的将是前字符串前n个;如果传入的是const string& s,加在后面的的是除去前n个所剩下的字符串


5、查找和替换

作用:

查找:查找指定字符串

替换:在指定的位置替换字符串

函数:

/* 字符串查找与替换
 找第一次
int find(const string& s,int pos = 0)const;	 1从pos位置查找字符串s第一次出现位置
int find(const char* s,int pos = 0)const;	 2从pos位置查找字符串s第一次出现位置
int find(const char* s,int pos,int n)const;	 3从pos位置查找字符串s的前n个字符第一次出现位置
int find(const char c,int pos = 0)const;	 4从pos位置查找字符c第一次出现位置
 找最后一次
int rfind(const string& s,int pos = npos)const; 5从pos位置查找字符串s最后一次出现位置
int rfind(const char* s,int pos = npos)const;	6从pos位置查找字符串s最后一次出现位置
int rfind(const char* s,int pos,int n)const;	7从pos位置查找字符串s前n个字符最后一次出现位置
int rfind(const char c,int pos = 0)const;		8从pos位置查找字符c最后一次出现位置
 替换
string& replace(int pos,int n,const string& s); 9将pos位置开始n个字符替换为字符串s
string& replace(int pos,int n,const char* s);  10将pos位置开始n个字符替换为字符串s
*/

注意,find从左往右找,rfind从右往左找,但2个都是从左向右计数,找到返回位置,否则返回-1

查找: 

void test04()
{
	// 查找
	string s1 = "abcdefgcd";
	int pos = s1.find("cd"); // 不传pos则默认从0开始找字符cd第一次出现位置
	cout << pos << endl;
	pos = s1.rfind("cd");// 不传pos则默认从0开始找字符cd最后一次出现位置
	cout << pos << endl;

	int pos1 = s1.find("cd", 3);// 从3开始找字符cd第一次出现位置
	cout << pos1 << endl;
	pos1 = s1.rfind("cd",3);	// 从3开始找字符cd最后一次出现位置
	cout << pos1 << endl;

	int pos2 = s1.find("cd", 3, 1); // 从3开始找字符串cd的前1个字符第一次出现位置
	cout << pos2 << endl;
	pos2 = s1.rfind("cd", 3, 1); // 从3开始找字符串cd的前1个字符最后一次出现位置
	cout << pos2 << endl;
}

 注意,a是0位置,b是1位置....

替换: 

void test05()
{
	// 替换
	string s1 = "abcdefgcd";
	string str = " hello my ";
	s1.replace(2, 5, str);// 从2开始前5个字符替换为str
	cout << s1 << endl;
}


6、字符串比较

作用:进行字符串之间的比较

比较方式:逐个按字符的ASCII码进行对比

=返回0

>返回1

<返回-1

函数:

/*字符串比较
int compare(const string& s)const;  与字符串s比较
int compare(const char* s)const;    与字符串s比较
*/

测试:

void test06()
{
	string s1 = "abcdefg";
	string s2 = "abcdefg"; // 等于 0
	string s3 = "abcdef";  // 大于 1
	string s4 = "abcdefgh";// 小于 -1
	int ret = s1.compare(s2);
	cout << ret << endl;
	ret = s1.compare(s3);
	cout << ret << endl;
	ret = s1.compare(s4);
	cout << ret << endl;
}

其实compare最大用处在于对比字符串是否相等 


7、字符存取

作用:存取string中单个字符

/*字符存取
char& operator[](int n);  通过[]读取字符
char& at(int n);		  通过at方法获取字符
*/

①读字符

void test07()
{
	// 1 通过[]方式读取字符
	string s = "Type here";
	for (int i = 0; i < s.size(); i++)
	{					// .size()可以返回字符s的长度
		cout << s[i] << " ";
	}
	cout << endl;
	// 2 通过at方式读取字符
	for (int i = 0; i < s.size(); i++)
	{
		cout << s.at(i) << " ";
	}
}

②修改字符 

	// 通过[]修改字符
	s[0] = 't';
	cout << s << endl;
	// 通过at修改字符
	s.at(1) = 'Y';
	cout << s << endl;


8、插入与删除

作用:对字符串进行插入和删除操作

函数:

/*插入和删除
 string& insert(int pos,const char* s);  在pos位置插入字符串s
 string& insert(int pos,const string& s);在pos位置插入字符串s
 string& insert(int pos,int n,char c);   在pos位置插入n个字符c
 string& erase(int pos,int n = npos);    删除从pos开始的n个字符
*/
void test08()
{
	string s1 = "Type here";
	s1.insert(0, "ok");   // 1 char* 从0开始加上ok字符
	cout << s1 << endl;

	string s2 = "ko";
	s1.insert(0, s2);     // 2 string& 从0开始加上ko字符
	cout << s1 << endl;

	s1.insert(0, 8, '+'); // 3 从0开始加上8个字符+
	cout << s1 << endl;

	s1.erase(0, 12);      // 4 从位置0开始删除okko4个和8个+一共12个字符
	cout << s1 << endl;
}

9、获取字串

作用:从字符串中获取想要的字串

函数:

/* 获取字串
string substr(int pos,int n=npos)const; // 返回由pos开始n个字符组成的字符串
*/

测试:

void test09()
{
	string s1 = "Type there";
	string s2 = s1.substr(5, 5);
	cout << s2 << endl;
}

 实际使用举例:

void test10()
{
	string user_email = "Joyce@Gmail.com";
	// 根据邮箱获取用户名称
	int pos = user_email.find('@');// 从email中读取@字符所在的位置,这里是位置5
	string user_name = user_email.substr(0, pos); // 截取0-5的字符
	cout << user_name << endl;
}

以上就是string容器的所有内容


二、vector容器

1、基本概念

功能:vector数据结构与数组十分相似,也称为单端数组

区别:数组是静态空间,确定大小后无法扩展,vector可以动态扩展

动态扩展:为防止在vector原空间之后没有可用空间来扩展,其动态扩展实际上是重新寻找一块更大的空间,先将原有数据拷贝进去,再释放原空间

如图,有这些迭代器,常用的是v.begin()与v.end()。 

而vector的迭代器是支持随机访问的迭代器


2、构造函数

功能:即创建vector容器

/*构造函数
vector<T> v;			   1使用模板实现类的实现,默认构造函数
vector(v.begin(),v.end()); 2将v[v.begin(),v.end())区间中的元素赋给自身,注意区间左闭右开
vector(n,elem);			   3将n个elem元素拷贝给自身
vector(const vector& v);   4拷贝构造函数,将v拷贝给自身
*/
void test01()
{
	vector<int> v1; // 1默认构造
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	printV(v1);

	vector<int> v2(v1.begin(), v1.end()); // 2
	printV(v2);

	vector<int> v3(10, 888); // 3,10个888赋给v3
	printV(v3);

	vector<int>v4(v3); // 4拷贝构造
	printV(v4);
}

额外的,我再实现一个打印容器中数据的函数printV

void printV(vector<int>& v)
{
	for (vector<int>::iterator it=v.begin();it<v.end();it++)
	{
		cout << *it<< " ";
	}
	cout << endl;
}

 运行:


3、赋值操作

功能:给vector容器赋值

/*赋值操作
vector& operator=(const vector& v); 1 =赋值,重载=运算符
assign(begin,end);					2 将[begin,end)区间中的数据赋给自身,注意区间左闭右开
assign(n,elem);						3 将n个elem赋给自身
*/
void test02()
{
	vector<int>  v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);

	vector<int> v2;
	v2 = v1;			// 1 直接=赋值
	printV(v2);

	vector<int> v3;
	v3.assign(v2.begin(), v2.end()); // 2 区间赋值
	printV(v3);

	vector<int> v4;
	v4.assign(10, 888); // 3 将10个888赋给自身
	printV(v4);
}


4、容量和大小

功能:对vector容器的容量和大小进行操作

/*容量和大小
v.empty();			 判断容器是否为空,空返回true否则false
v.capacity();		 返回容器容量
v.size();		   	 返回容器当前大小
v.resize(int n);	 重新指定容器长度为n,若容器变长,则以默认值0填充新位置。
									   	  若容器变短,则末尾超出容器长度的元素被删除
v.resize(int n,elem);重新指定容器长度为n,若容器变长,则以elem填充新位置。
										  若容器变短,则末尾超出容器长度的元素被删除
*/

①容量与大小的输出

void test03() // 判断为空、容量、大小
{
	vector<int> v1; 
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	printV(v1);

	cout << v1.empty() << endl;		// 判断为空,ture=1,false=0
	cout << v1.capacity() << endl;  // 容量
	cout << v1.size() << endl;		// 大小
}

 ②修改size

void test04()
{
	vector<int> v1;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	printV(v1);
	vector<int> v2 = v1; // v1赋给v2
	v2.resize(16);	// 变长,默认用0填充
	printV(v2);
	v2.resize(5);	// 变短
	printV(v2);
	v2.resize(16, 'm'); // 变长且更换元素
	printV(v2);
}


5、插入和删除

功能:对vector容器进行插入与删除的操作

/*插入与删除
v.push_back(elem);			 尾部插入elem元素
v.pop_back();				 删除尾部最后一个元素
v.insert(const_iterator pos,elem);				  在迭代器指向的pos位置插入元素elem
v.insert(const_iterator pos,int n,elem);		  在迭代器指向的pos位置插入n个elem元素
v.erase(const_iterator pos); 删除迭代器指向的pos位置的元素
v.erase(const_iterator start,const_iterator end); 删除迭代器指向的从start到end区间的元素
v.clear();					 删除容器中所有元素
*/

测试:

void test05()
{
	vector<int>  v1; 
	v1.push_back(1);			 // 1尾插元素
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	printV(v1);

	v1.pop_back();				 // 2尾删元素
	v1.pop_back();
	printV(v1);

	v1.insert(v1.begin(), 'x');  // 3在begin位置插入元素'x',
	printV(v1);

	v1.insert(v1.end(), 10, 888);// 4在end位置插入10个888
	printV(v1);

	v1.erase(v1.begin());		 // 5删除begin位置的元素 头删元素
	printV(v1);

	v1.erase(v1.begin()+2, v1.end()); // 6删除下标为2开始到end区间内的元素
	printV(v1);

	v1.clear();					 // 7清空所有元素
	printV(v1);
}


6、数据存取

功能:对vector容器中的元素进行读取与存储

/*数据存取
v.at(int pos);	1返回pos位置处的元素
operator[pos];	2重载[],也返回pos处的元素
v.front();		3返回容器中第一个元素
v.back();		4返回容器中最后一个元素
*/

测试:

void test06()
{
	vector<int> v1;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	printV(v1);

	cout << v1.at(3) << endl;  // 1返回位置3处的元素
	cout << v1[3] << endl;	   // 2返回位置3处的元素
	cout << v1.front() << endl;// 3返回容器中第一个元素
	cout << v1.back() << endl; // 4返回容器中最后一个元素
}


7、互换容器

功能:实现两个容器内元素进行互换

// v1.swap(v2); 将v2的元素与自身v1交换 

测试:

void test07()
{
	vector<int> v1;
	for (int i = 0; i < 10; i++)
	{ // 给v1初始化
		v1.push_back(i);
	}
	cout << " v1:";
	printV(v1);

	vector<int> v2;
	for (int i = 9; i >= 0; i--)
	{ // 给v2初始化
		v2.push_back(i);
	}
	cout << " v2:";
	printV(v2);

	v1.swap(v2);  // 交换v1与v2的元素
	cout << " v1:";
	printV(v1);
	cout << " v2:";
	printV(v2);
}

 实际用途:如收缩容器

我们创建一个vector容器v1,在其中存入888888个元素

	vector<int> v1;
	for (int i = 0; i < 888888; i++)
	{
		v1.push_back(i);
	}
	cout << v1.capacity() << endl;  // 容量
	cout << v1.size() << endl;		// 大小

打印输出容器的容量与大小

容量是1049869,大小是888888

接下来,我们使用resize函数重新指定容器大小为5

	v1.resize(5);
	cout << v1.capacity() << endl;  // 容量
	cout << v1.size() << endl;		// 大小

输出容器容量与大小

可以发现,容器的容量仍然是1049869,而大小却只有5个元素 ,这样就极大的浪费了空间

接下来我们使用swap函数解决:

	vector<int>(v1).swap(v1);
	cout << v1.capacity() << endl;  // 容量
	cout << v1.size() << endl;		// 大小

 这样就解决了浪费空间的问题

原理:

 这是resize后的v1,使用的大小很小一点,容量很大

 接下来使用vector<int>(v1).swap(v1);函数

首先,前面的

 vector<int>(v1)是创建一个匿名对象,它会使用v1的实际使用大小来初始化一个新的对象,假设是v2

v2的空间就是:一小点

 然后,后面的.swap(v1)就是将匿名对象创建的对象(v2)与v1交换元素

 这样就实现了v1交换到了同样数据但容量更小的容器


8、预留空间

功能:减少vector在动态扩展时的扩展次数

 v.reserve(int len); 容器预留len个长度空间,但不初始化这块空间,因此元素不可访问

测试:

①我们创建容器v1,为其开辟888888个元素空间,并使用number计数与指针p记录容器首元素的地址,如果容器首元素的地址改变,则说明容器发生了扩容

vector<int> v1;
	int number = 0; // 计数
	int* p = NULL;  // 保存首地址
	for (int i = 0; i < 888888; i++)
	{
		v1.push_back(i);
		if (p != &v1[0]) // 如果v1的首元素地址变了,就是重新开辟内存了
		{
			p = &v1[0];
			number++;// 计数+1
		}
	}
	cout << number << endl;

可以看到,为使容器开辟到888888个元素空间,容器一共扩展35次

②接下来,我们使用reserve函数为容器预留888889空间 ,然后重复①的代码

vector<int> v2;
	int number1 = 0; // 计数
	v2.reserve(888889); // 预留888889空间
	int* p1 = NULL;  // 保存首地址
	for (int i = 0; i < 888888; i++)
	{
		v2.push_back(i);
		if (p1 != &v2[0]) // 如果v1的首元素地址变了,就是重新开辟内存了
		{
			p1 = &v2[0];
			number1++;// 计数+1
		}
	}
	cout << number1 << endl;

可以看到只有1次,是我们最初初始化的那一次 

因此,如果我们要使用较大的空间,可以一开始就预留一部分很大的空间

以上就是vector容器的全部内容


三、deque容器

1、基本概念

deque :double ended queue ,双端队列

功能:

相当于一个双端数组,可以对头部和尾部进行插入与删除操作,但其空间并不完全连续

与vector的区别:

①vector对于头部的插入效率低,要先将数据向后移动才能插入,数据越多,效率越低

②deque对头部的插入与删除操作效率高

③vector访问元素时速度更快

 同样的,deque容器也有很多迭代器,不过多了头插与头删等。

duque工作原理:

deque内部有个中控器,其中维护的是每个缓冲区的地址,而缓冲区中存放的是真实的数据

 当一片缓冲区满了后,会再找另一片缓冲区存入元素,使得我们使用deque容器时似乎它是一片连续的空间

而同时,由于每次寻找元素都要先找到中控器中的地址,所以它效率比vector低

而deque容器的迭代器也支持随机访问


 首先,我们实现一个打印函数,以打印出所有我们创建出的deque容器的值

void printD(deque<int> d)
{
	for (deque<int>::iterator it = d.begin(); it != d.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

而为了防止it在遍历时被修改(使容器为只读状态),我们可以在参数列表前加上const,但这样,循环里的迭代器也要加上const:

void printD(const deque<int> d) // 加上const
{
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
	{			// 改成const_iterator
		cout << *it << " ";
	}
	cout << endl;
}

2、构造函数

/*构造函数
deque<T> deqT;		1默认构造函数
deque(begin,end);	2将[begin,end)区间中的元素拷贝给自身,注意区间左闭右开
deque(n,elem);		3将n个elem拷贝给自身
deque(const deque &deq); 4拷贝构造函数,将deq拷贝给自身
*/

测试:

void test01()
{
	deque<int> d; // 1默认构造	
	for (int i = 0; i < 10; i++)
	{
		d.push_back(i);
	}
	printD(d);

	deque<int> d1(d.begin() + 2, d.end()-3); // 2将d的区间[2,6)中的数据拷贝给d1
	printD(d1);

	deque<int> d2(8, 888); // 3将8个888赋给自身d2
	printD(d2);

	deque<int> d3(d2); // 4将d2拷贝构造给自身d3
	printD(d3);
}


3、赋值操作

功能:给deque容器赋值

/*赋值操作
deque& operator=(const deque& deq); 1就是重载=操作符
deq.assign(begin,end);			2将[begin,end)区间中的元素拷贝给自身,注意区间左闭右开
deq.assign(n,elem);				3将n个elem拷贝给自身
*/

测试:

void test02()
{
	deque<int> d1; 
	for (int i = 0; i < 10; i++)
	{
		d1.push_back(i);
	}
	printD(d1);

	deque<int> d2 = d1; // 1直接=赋值
	printD(d2);

	deque<int> d3;
	d3.assign(d2.begin() + 2, d2.end() - 3); // 2将d2的区间[2,6)中的数据拷贝给d3
	printD(d3);

	deque<int> d4;
	d4.assign(8,66); // 3将8个66赋给自身
	printD(d4);
}


4、容量和大小

功能:对deque容量的容量和大小进行操作

/*容量和大小
deq.empty();		 1判断容器是否为空,空返回true否则false
deq.size();		   	 2返回容器当前大小
deq.resize(int n);	 3重新指定容器长度为n,若容器变长,则以默认值0填充新位置。
									   	  若容器变短,则末尾超出容器长度的元素被删除
deq.resize(int n,elem);4重新指定容器长度为n,若容器变长,则以elem填充新位置。
										  若容器变短,则末尾超出容器长度的元素被删除
*/

测试:

void test03() // 判断为空、容量、大小
{
	deque<int> d1; 
	for (int i = 0; i < 10; i++)
	{
		d1.push_back(i);
	}
	printD(d1);

	cout << d1.empty() << endl;		// 1判断为空,ture=1,false=0
	cout << d1.size() << endl;		// 2返回大小

	d1.resize(15); // 3变长 ,默认值为0
	printD(d1);

	d1.resize(20,'v'); // 3变长,默认为为118
	printD(d1);

	d1.resize(5); // 4变短
	printD(d1);
}

5、插入与删除

功能:向deque容器中插入和删除数据

/*插入与删除
d.push_front(elem);			1 头插元素
d.pop_front();				2.头删元素
d.push_back(elem);			3 尾部插入elem元素
d.pop_back();				4 删除尾部最后一个元素
d.insert( iterator pos,elem);		5 在迭代器指向的pos位置插入元素elem的拷贝,返回新数据的位置
d.insert( iterator pos,int n,elem);	6 在迭代器指向的pos位置插入n个elem元素,无返回值
d.insert(iterator  pos,begin,end);	7 在迭代器指向的pos位置插入区间[begin,end)的元素,无返回值,注意区间左闭右开
d.erase( iterator pos);				8 删除迭代器指向的pos位置的元素,返回下一个元素的位置
d.erase( begin,end);		9 删除begin到end区间的元素,返回下一个元素的位置
d.clear();					10 删除容器中所有元素
*/

测试:

void test04()
{
	deque<int> d1;
	d1.push_front(10); // 1头插10与30
	d1.push_front(30);
	d1.push_back(3); // 3尾插3与1
	d1.push_back(1);
	// 顺序:30 10 3 1
	printD(d1);

	d1.pop_back();	// 4尾删
	d1.pop_front(); // 2头删
	printD(d1);

	d1.insert(d1.begin() + 1, 5); // 5在d1.begin后一个位置插入元素5
	printD(d1);
	
	d1.insert(d1.end(), 5, 888);  // 6在d1.end位置插入5个888
	printD(d1);

	d1.insert(d1.begin() + 2, d1.begin() + 2, d1.end() - 1); 
	// 7在d1.begin+2的位置插入d1容器中区间[d1.begin+2,d1.end-1)中的元素
	printD(d1);

	d1.erase(d1.begin()+1); // 8删除d1.begin+1位置的元素 3
	printD(d1);

	d1.erase(d1.begin() + 1,d1.end()-3); // 9删除区间d1.begin+1到d1.end之间的元素
	printD(d1);

	d1.clear();   // 清空
	printD(d1); 
}

一个printD函数对应一行数据 


6、数据存取

功能:对deque中的容量进行存取操作

/*数据存取
d.at(int pos);	1返回pos位置处的元素
operator[pos];	2重载[],也返回pos处的元素
d.front();		3返回容器中第一个元素
d.back();		4返回容器中最后一个元素
*/

测试:

void test05()
{
	deque<int> d1;
	for (int i = 0; i < 10; i++)
	{
		d1.push_back(i);
	}
	printD(d1);
	cout << d1.at(5) << endl;
	cout << d1[5] << endl;
	cout << d1.front() << endl;
	cout << d1.back() << endl;
}


7、排序

功能:对deque中的元素进行排序

算法:

// 排序
//  sort(iterator begin,iterator end); 对区间begin到end中间的元素进行排序
#include<algorithm>	// 标准算法头文件

记得包含标准算法头文件

测试:

void test06()
{
	deque<int> d1;
	srand((unsigned)time(NULL));
	for (int i = 0; i < 15; i++)
	{
		int num = rand()%100; // 随机数
		d1.push_back(num); // 尾插
	}
	printD(d1);

	sort(d1.begin(), d1.end()); // 进行升序排序
	printD(d1);
}

 vector容器也可以

总结:对于支持随机访问的迭代器的容器,都可以用sort算法直接进行排序


四、案例:评委打分

1、案例说明:

有5名选手:ABCDE,10个评委分别对每一位选手打分,分数从60-100之间,去除最高分和最低分,取出每位选手的平均分

2、实现步骤:

①创建选手类person,内包含name与score属性,并创建五名选手,将选手放到vector容器中

②遍历vector容器中的选手,为每一位选手进行打分并将分数存入deque容器中

③分别对每位选手的分数进行排序,然后去除最高分和最低分

④累加剩下的分数并取平均值,存入选手的score属性中

⑤输出打印选手与平均分

// 选手类
class person
{
public:
	person(string name, int score)
	{
		this->m_name = name;
		this->m_score = score;
	}
	string m_name; //姓名
	int m_score;  // 平均分
};
// 创建选手,并初始化姓名与分数
void createPlayer(vector<person>& v)
{
	string name_seed = "ABCDE"; // 名称种子
	for (int i = 0; i < 5; i++)
	{
		string name = "选手";
		name += name_seed[i];
		int score = 0; // 初始化分数
		person p(name, score); // 创建选手
		v.push_back(p); // 将选手插入到容器
	}
}

注意,给选手打分有2种方法:

①是手动输入,直接cin 10个分数

②是直接随机数生成10个

我这里使用方法② 

// 打分并取均值,存储到选手属性中
#include<ctime>// 获取系统时间的头文件
void setScore(vector<person>& v)
{
	srand((unsigned int)time(NULL)); // 随机数种子
	// 使用双头数组deque存储分数
	for (vector<person>::iterator it = v.begin(); it != v.end(); it++)
	{
		deque<int>d;
		//cout << "该选手分数分别为";
		for (int i = 0; i < 10; i++)
		{
			int score = rand() % 41 + 60; // 随机生成60-100之间的数
					//       0 - 40
			//cout << score << " ";
			d.push_back(score);
		}
		sort(d.begin(),d.end()); // 从小到大排序
		d.pop_front(); // 去除最小值
		d.pop_back();  // 去除最大值
		// 取平均分
		int sum = 0;
		int i = 10;

		for (deque<int>::iterator it = d.begin(); it != d.end(); it++)
		{
			sum += *it; // 累加所有评委的打分
		}
		int avg = sum / d.size(); // 算出平均分
		it->m_score = avg; // 最外层循环,赋给选手的分数
		cout << endl;
	}
}
// 打印每位选手的姓名与分数
void print2(const vector<person> v) // 加上const
{
	for (vector<person>::const_iterator it = v.begin(); it != v.end(); it++)
	{			// 改成const_iterator
		cout << it->m_name << "分数为" << it->m_score << endl;
	}
	cout << endl;
}

以上就是案例的所有内容 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/520140.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Apache Hive

Hive的概念 Hive是Facebook开源出来&#xff0c;后来贡献给力Apache .宗旨是&#xff1a;提高分析数据的能力降低分析数据的开发成本。 Hive是基于 Hadoop 的一个数据仓库工具&#xff0c;用于分析数据的。 为什么说Hive是基于Hadoop的呢&#xff1f; ​ #作为一款数据仓库软件…

依次对两数组对应位置的元素进行逻辑判断numpy.logical_and()numpy.logical_or()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 依次对两数组对应位置的元素进行逻辑判断 numpy.logical_and() numpy.logical_or() [太阳]选择题 下列代码中np.logical_or(A, B)输出的结果是&#xff1f; import numpy as np A [True, Fa…

R语言 | 正态分布

目录 一、用直方图检验crabs对象 二、用直方图检验beaver2对象 三、用QQ图检验数据是否服从正态分布 四、shapiro.test()函数 所谓正态分布又称高斯分布&#xff0c;许多统计学的理论都是假设所使用的数据服从正态分布。 一、用直方图检验crabs对象 检验数据是否服从正态分…

Kubernetes❀ 详细教程-介绍

Kubernetes❀ 详细教程-介绍 Kubernetes详细教程-介绍1. Kubernetes介绍1.1 应用部署方式演变1.2 kubernetes简介1.3 kubernetes组件1.4 kubernetes概念 Kubernetes详细教程-介绍 1. Kubernetes介绍 1.1 应用部署方式演变 在部署应用程序的方式上&#xff0c;主要经历了三个…

c++ 一个简单的请求程序

https://github.com/AHUT-GeekTeam/ESP32CAM_BaiduAI/blob/master/demo.ino HTTP格式 请求行 回车换行请求头 回车换行请求头 回车换行请求头 回车换行……请求头 回车换行 回车换行数据 jichu daima 参考黑马程序员的代码MAIN.C #include "b.h" //#include <p…

威纶通触摸屏复合式多功能按钮的使用方法

威纶通触摸屏复合式多功能按钮的使用方法 如下图所示,打开easy builder pro软件,新建一个测试项目,在元件中找到复合式多功能按钮,点击后放入画面中, 如下图所示,此时会弹出以下窗口,在动作中点击“+”图标,选择自己需要添加的动作, 如下图所示,首先添加一个位状…

C++类与对象—下

本期我们继续学习类与对象&#xff0c;没有看过上和中的小伙伴建议先看前两期内容 (2条消息) C类与对象—上_KLZUQ的博客-CSDN博客 (2条消息) C类与对象—中_KLZUQ的博客-CSDN博客 目录 1.再谈构造函数 1.1构造函数体赋值 1.2初始化列表 1.3 explicit关键字 2. static成员…

学成在线笔记+踩坑(12)——用户认证

导航&#xff1a; 【黑马Java笔记踩坑汇总】JavaSEJavaWebSSMSpringBoot瑞吉外卖SpringCloud黑马旅游谷粒商城学成在线牛客面试题 目录 1 需求分析 2 【认证模块】连接用户中心数据库 2.1 连接数据库认证 2.1.1 分析 2.1.2 实现&#xff0c;实现UserDetailsService接口 …

Golang每日一练(leetDay0064) 轮转数组、颠倒二进制位

目录 189. 轮转数组 Rotate Array &#x1f31f;&#x1f31f; 190. 颠倒二进制位 Reverse Bits &#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 189. 轮转数组 Rotate Ar…

小曾同学【五周年创作纪念日】——努力向前冲的菜鸟

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c; 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。&#x1f60a; 座右铭&#xff1a;不想当开发的测试&#xff0c;不是一个好…

什么是UA?常见蜘蛛UA?怎么查询UA?

什么是UA? UA简介查看自己的UA修改它的常见用处搜索引擎蜘蛛UA大全常见蜘蛛UA标识 UA简介 UA其实是User Agent的简称。 所谓的User Agent其实就是浏览器在跟服务器通信的时候&#xff0c;一段百十来个字符的落款信息罢了。浏览器发送的每一个HTTP请求数据的头部都加了这个信息…

【C++】红黑树的插入分析及验证

文章目录 1. 红黑树概念2. 红黑树性质3. 结构定义关于默认节点为红/黑色的讨论 4. insert情况1—— uncle节点存在且为红色(g p c左斜形成一条直线)情况2——uncle节点不存在/存在且为黑色(g p c 左斜形成直线 右单旋)uncle节点不存在uncle节点存在并且为黑色 情况3——uncle节…

第7章链接:编译器驱动程序

示例程序由两个源文件组成&#xff0c;main.c 和 swap.c。 main函数初始化一个两元素的整数数组&#xff0c;然后调用swap函数来交换这一对数。 main.c void swap();int buf[2] {1, 2};int main() {swap();return 0; }swap.c extern int buf[];int *bufp0 &buf[0]; i…

【Java】Java中线程安全有哪些实现思路?

文章目录 1、使用 synchronized 关键字2、使用 ReentrantLock 类3、使用 ConcurrentHashMap 类4、使用 Atomic 类5、使用 ThreadLocal 类总结 在 Java 多线程编程中&#xff0c;线程安全是一个非常重要的概念。 线程安全通常指程序在多线程并发执行时&#xff0c;仍然能够保持正…

迄今为止,最强ChatGPT写论文技巧,总共6步,手把手告诉你

目录 第一步&#xff1a;现象确认 第三步&#xff1a;定位优质学术资源 第四步&#xff1a;对比分析 第五步&#xff1a;深挖启示 & 第六步&#xff1a;写论文 代写论文&#xff0c;不知道有多少朋友听说过&#xff0c;这是一门严格来说有点小众&#xff0c;但盈利空间…

常见问题解答:如何有效使用 Facebook 商务管理平台(BM)?

Facebook 商务管理平台&#xff08;BM&#xff09;是一个功能强大的工具&#xff0c;可帮助广告主在 Facebook 平台上管理和优化广告投放。然而&#xff0c;对于初次接触 BM 的用户来说&#xff0c;可能会遇到一些问题和困惑。本文将回答一些常见问题&#xff0c;帮助您更有效地…

如何使用分布式存储系统促进 AI 模型训练

在处理小型数据集和简单算法时&#xff0c;传统的机器学习模型可以存储在独立机器或本地硬盘驱动器上。然而&#xff0c;随着深度学习的发展&#xff0c;团队在处理更大的数据集和更复杂的算法时越来越多地遇到存储瓶颈。 这凸显了分布式存储在人工智能&#xff08;AI&#xf…

半监督学习笔记

聚类假设 假设输入数据点形成簇&#xff0c;每个簇对应于一个输出类&#xff0c;那么如果点在同一个簇中&#xff0c;则它们可以认为属于同一类。聚类假设也可以被视为低密度分离假设&#xff0c;即&#xff1a;给定的决策边界位于低密度地区。两个假设之间的关系很容易看出。一…

C++ 智能指针的原理、分类、使用

1. 智能指针介绍 为解决裸指针可能导致的内存泄漏问题。如&#xff1a; a&#xff09;忘记释放内存&#xff1b; b&#xff09;程序提前退出导致资源释放代码未执行到。 就出现了智能指针&#xff0c;能够做到资源的自动释放。 2. 智能指针的原理和简单实现 2.1 智能指针的原…

讯飞星火 VS 文心一言:谁是中文大语言模型的TOP1?

在百度发布文心一言一个多月后&#xff0c;科大讯飞也发布了自己的大模型“讯飞星火大模型”。本篇博客就测评一下这两个在中文圈最受好评的大语言模型&#xff0c;顺便辅以ChatGPT为参考。大家一起来看看到底谁是中文大语言模型的TOP1&#xff1f; 目录 体验网址 1、旅游攻…