P186 20
vector指向量,可以理解为“变长数组”,长度根据需要而自动改变的数组。有时会碰到普通数组会超过内存的情况,可以使用vector解决。
而且,vector可以用来以邻接表的方式存储图,可以解决当节点数太多,无法使用邻接矩阵,又害怕使用指针实现邻接表的时候,使用很简单。
一、vector容器
vector是一种类模板,是一种顺序容器。顺序容器是按照是按照元素在标准库里边的顺序保存和访问的。
1.vector存放内置数据类型
#include<iostream>
#include<vector>
using namespace std;
//vector存放内置数据类型
void test01()
{
//创建一个vector容器,(数组)
vector<int> v;
//向容器中插入数据
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
}
int main()
{
test01();
return 0;
}
1.六种遍历方式
六种遍历方式,完整代码总览
//遍历方式1,采用迭代器
for (vector::iterator it = vec.begin(); it != ovec.end(); it++)
{
cout << *it << endl;
}
//遍历方式2,采用迭代器.并采用C++11新标准中的auto关键字
for (auto it = vec.begin(); it != vec.end();it++)
{
cout << *it << endl;
}
//遍历方式3,while (itBegin != itEnd)
while (itBegin != itEnd)
{
cout << *itBegin << endl;
itBegin++;
}
//遍历方式4,采用下标进行数据元素访问
for (size_t i = 0; i < vec.size(); i++)
{
cout << vec[i]<< endl
}
//遍历方式5,采用C++11新标准中的auto关键字
for (auto i:vec)
{
cout << i<< endl;
}
//第6种遍历 利用STL提供的算法
for_each(v.begin(), v.end(), myPrint);
部分遍历详解
第一种遍历方式
//通过迭代器访问容器中的数据
vector<int>::iterator itBegin = v.begin();//起始迭代器 指向容器中第一个元素
vector<int>::iterator itEnd = v.end();// 结束迭代器 指向容器中做后一个元素的下一个位置
//第一种遍历方式
while (itBegin != itEnd)
{
cout << *itBegin << endl;
itBegin++;
}
第二种遍历方式
//第二种遍历方式
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
cout << *it << endl;
第三种遍历 利用STL提供的算法
遍历前需要
1.添加头文件#include//标准算法的头文件
2.添加一个打印函数
void myPrint(int val)
{
cout << val << endl;
}
//第三种遍历 利用STL提供的算法
for_each(v.begin(), v.end(), myPrint);
2 初始化,区别
1 默认初始化,无参(没给定数组大小)
vector<int> res;; 默认初始化
vector为空, size为0,表明容器中没有元素,而且 capacity 也返回 0,意味着还没有分配内存空间。
这种初始化方式适用于元素个数未知,需要在程序中动态添加的情况;
添加元素,只能用.push_back();
for (int i = 10; i < 18; i++)
res.push_back(i);
以下下错误,因为还没有分配内存空间。
for (int i = 10; i < 18; i++)
res[i] = i;
2 带参数构造初始化 (给定数组大小、初始值)
vector<int> res(8);
res中将包含8个元素,每个元素进行缺省的值初始化,对于int,也就是被赋值为0,因此res被初始化为包含8个0。
等同于
vector<int> res(8,0);
指定值初始化,ilist5被初始化为包含7个值为3的int。
vector<int> ilist5(7,3);
添加元素,可用res[i] = a;也可.push_back(a);
for (int i = 0; i < 8; i++)
res.push_back(i);
for (int i = 0; i < 8; i++)
res[i] = i;
但是,res[i] = a;这种数组下标只允许在数组长度以内,比如本例0~8;
下面for循环0~10越界,11 ~13,起点都不在范围内,都会报错;
for (int i = 0; i < 10; i++) res[i] = i;
for (int i = 11; i < 15; i++) res[i] = i;
而对于 res.push_back(a);没有限制的,因为他是在前面定长数组尾部动态追加的;
for (int i = 0; i < 8; i++) res.push_back(i);
3. 1 2 两种初始化特点对比测试
//定义数组
vector<int> res(8);
cout << "res.size() = " << res.size() << endl;
//给数组重新赋值
for (int i = 0; i < 8; i++)
res[i] = i;
//输出
for (int i = 0; i < res.size(); i++)
cout << res[i] << endl;
cout << "res.size() = " << res.size() << endl;
//定义数组
vector<int> res(8);
cout << "res.size() = " << res.size() << endl;
//给数组重新赋值
for (int i = 0; i < 8; i++)
res.push_back(i);
//输出
for (int i = 0; i < res.size(); i++)
cout << res[i] << endl;
cout << "res.size() = " << res.size() << endl;
4 通过同类型的vector进行初始化
vector<int> ilist2(ilist);
vector<int> ilist2 = ilist;
这两种方式等价 ,ilist2 初始化为ilist的拷贝,ilist必须与ilist2 类型相同,也就是同为int的vector类型,ilist2将具有和ilist相同的容量和元素。
5.通过迭代器进行初始化
vector<int> ilist3(ilist.begin()+2,ilist.end()-1);
ilist3初始化为两个迭代器指定范围中元素的拷贝,范围中的元素类型必须与ilist3 的元素类型相容,在本例中ilist3被初始化为{3,4,5,6}`。
这种初始化方法特别适合于获取一个序列的子序列。
6 .带参数构造初始化
vector<int> ilist5(7,3);
指定值初始化,ilist5被初始化为包含7个值为3的int。
7 通过数组地址初始化
int a[5]={1,2,3,4,5}
vector<int> vec_i(a,a+5);
8 直接用{ }初始化
vector<int> vec={1,2,3,4,5,6,7,8,9}
9 初始为二维数组
vector<vector<int>> arr(8,vector<int>(8,0));
8*8的二维数组,元素都是0;
3.vector存放自定义的数据类型
1.自定义数据类型
#include<iostream>
#include<vector>
using namespace std;
//vector存放自定义数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
void test01()
{
//创建一个vector容器,(数组)
vector<Person> v;
Person p1("a",10);
Person p2("b", 20);
Person p3("c", 30);
Person p4("d", 40);
//向容器中插入数据
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
//遍历容器中的数据
for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
//cout << "姓名:" <<(*it).m_Name <<" 年龄:"<<(*it).m_Age<< endl;
cout << "姓名:" << it->m_Name << " 年龄:" << it->m_Age << endl;
}
int main()
{
test01();
return 0;
}
//遍历容器中的数据
//两种输出方式
for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
//cout << "姓名:" <<(*it).m_Name <<" 年龄:"<<(*it).m_Age<< endl;
cout << "姓名:" << it->m_Name << " 年龄:" << it->m_Age << endl;
2.自定义数据类型 指针
test()中稍加修改,其他不变
void test02()
{
//创建一个vector容器,(数组)
vector<Person *> v;//Person*
Person p1("a", 10);
Person p2("b", 20);
Person p3("c", 30);
Person p4("d", 40);
//向容器中插入数据
v.push_back(&p1);
v.push_back(&p2);
v.push_back(&p3);
v.push_back(&p4);
//遍历容器中的数据
for (vector<Person *>::iterator it = v.begin(); it != v.end(); it++)
cout << "姓名:" <<(*it)->m_Name <<" 年龄:"<<(*it)->m_Age<< endl;
}
4.vector容器嵌套容器
学习目标:容器中嵌套容器,我们将所有数据进行遍历输出
#include<iostream>
#include<vector>
using namespace std;
//容器嵌套容器
void test02()
{
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 + 1);
v2.push_back(i + 2);
v3.push_back(i + 3);
v4.push_back(i + 4);
v5.push_back(i + 5);
}
//将小容器插入到大容器中
v.push_back(v1);
v.push_back(v2);
v.push_back(v3);
v.push_back(v4);
v.push_back(v5);
//通过大容器,把所有数据遍历一遍
for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++)
{
//(*it)-----容器 vector<int>
for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
{
cout << *vit << " ";
}
cout << endl;
}
}
int main()
{
test02();
return 0;
}
二、string容器
1.string基本概念
2.string构造函数
构造函数原型
-string(); //创建一个空的字符串例如:string str;
string(const char* s); //使用字符串s初始化
-string(const string& str); //使用一个string对象初始化另一个string对象
-string(int n, char c); //使用n个字符c初始化
程序
#include<iostream>
#include<vector>
using namespace std;
//string的构造函数
/*
-string(); //创建一个空的字符串例如:string str;
string(const char* s); //使用字符串s初始化
-string(const string& str); //使用一个string对象初始化另一个string对象
-string(int n, char c); //使用n个字符c初始化
*/
void test02()
{
string s1;//默认构造
const char* str = "hello world";
string s2(str);
cout << "s2=" << s2 << endl;
string s3(s2);
cout << "s3=" << s3 << endl;
string s4(10,'a');//10个a
cout << "s4=" << s4 << endl;
}
int main()
{
test02();
return 0;
}
3.string赋值操作
函数原型
-string& operator=(const char* s); // char*类型字符串赋值给当前的字符串
-string& operator=(const string &s) //把字符串s赋给当前的字符串
-string& operator=(char c) ; //字符赋值给当前的字符串
-string& assign(const char *s) ; //把字符串s赋给当前的字符串
-string& assign(const char *s, int n);//把字符串s的前n个字符赋给当前的字符串
-string& assign(const string &s) ; //把字符串s赋给当前字符串
-string& assign(int n,char c) ; //用n个字符c赋给当前字符串
程序
#include<iostream>
#include<vector>
using namespace std;
//string的赋值操作
/*
-string& operator=(const char* s); // char*类型字符串赋值给当前的字符串
-string& operator=(const string &s) //把字符串s赋给当前的字符串
-string& operator=(char c) ; //字符赋值给当前的字符串
-string& assign(const char *s) ; //把字符串s赋给当前的字符串
-string& assign(const char *s, int n); //把字符串s的前n个字符赋给当前的字符串
-string& assign(const string &s) ; //把字符串s赋给当前字符串
-string& assign(int n,char c) ; //用n个字符c赋给当前字符串
*/
void test02()
{
string str1;
str1 = "hello world";
cout << "str1=" << str1 << endl;
string str2;
str2 = str1;
cout << "str2=" << str2 << endl;
string str3;
str3 = 'a';
cout << "str3=" << str3 << endl;
string str4;
str4.assign("hello C++");
cout << "str4=" << str4 << endl;
string str5;
str5.assign("hello C++",5); //把字符串s的前n个字符赋给当前的字符串
cout << "str5=" << str5 << endl;
string str6;
str6.assign(str5); //把字符串s的前n个字符赋给当前的字符串
cout << "str6=" << str6 << endl;
string str7;
str7.assign(10,'w');
cout << "str7=" << str7 << endl;
}
int main()
{
test02();
return 0;
}
4.string的拼接操作
#include<iostream>
#include<vector>
using namespace std;
//string的赋值操作
/*
-string& operator+=(const char* str) ;//重载+=操作符
-string& operator+=(const char c);//重载+=操作符
-string& operator+=(const string& str);//重载+=操作符
-string& append (const char *s);//把字符串s连接到当前字符串结尾
-string& append(const char *s, int n) ;//把字符串s的前n个字符连接到当前字符串结尾
-string& append(const string &s);//同operator+=(const string& str)
-string& append(const string &s,int pos,int n);//字符串s中从pos开始的n个字符连接到字符串结尾
*/
void test02()
{
string str1="我";
str1 += "爱玩游戏";
cout << "str1=" << str1 << endl;
str1 += ":";
cout << "str1=" << str1 << endl;
string str2="LOL";
str1 += str2;
cout << "str1=" << str1 << endl;
str1.append(" and DNF");
cout << "str1=" << str1 << endl;
string str3 = "I ";
str3.append("love you !",5);
cout << "str3=" << str3 << endl;
str3.append("you !");
cout << "str3=" << str3 << endl;
string str4 = "我 ";
str4.append(str3,2,11);//下标从0开始
cout << "str4=" << str4 << endl;
}
int main()
{
test02();
return 0;
}
5.string查找和替换
功能描述:
·查找:查找指定字符串是否存在
·替换:在指定的位置替换字符串
函数原型
int find(const string& str, int pos = ) const;//查找str第一次出现位置,从pos开始查找
int find( const char* s , int pos = 0) const;//查找s第一次出现位置,从pos开始查找
int find(const char* s , int pos, int n) const;//从pos位置查找s的前n个字符第一次位置
int find(const char c, int pos = e) const;//查找字符c第一次出现位置
int rfind(const string& str, int pos = npos ) const;//查找str最后一次位置,从pos开始查找
int rfind(const char* s , int pos - npos ) const;//查找s最后一次出现位置,从pos开始查找
int rfind(const char* s, int pos, int n) const;//从pos查找s的前n个字符最后一次位置
int rfind(const char c, int pos = e) const;//查找字符c最后一次出现位置
string& replace(int pos, int n, const string& str);//替换从pos开始n个字符为字符串str
string& replace(int pos, int n,const char* s ) ;//替换从pos开始的n个字符为字符串s
1.查找
//rfind和find 区别
//find从左往右找;
//rfind从右往左找; 但是他们的pos还是按照从左往右的顺序的序号,下标从0开始
//1.查找
void test01()
{
string str1 = "abcdef";
//find
int pos = str1.find("de");
if (pos == -1)
cout << "未找到" << endl;
else
cout << "pos=" << pos << endl;
//rfind
//rfind和find 区别
//find从左往右找;
//rfind从右往左找; 但是他们的pos还是按照从左往右的顺序的序号,下标从0开始
int rpos = str1.rfind("de");
if (rpos == -1)
cout << "未找到" << endl;
else
cout << "rpos=" << rpos << endl;
}
注意:
虽然rfind从右往左找; 但是他们的pos还是按照从左往右的顺序的序号,下标从0开始
往我们把改成 string str1 = “abcdefde”;
find(de),从左往右第一个d下标为3;
rfind(de),从右往左第一个d下标为6;(下标顺序还是从左往右的)
//替换
//替换
void test02()
{
string str1 = "abcdef";
string str2 = "123456";
//从1号位置起,3个字符“bcd”替换为字符串str2的"123456"
str1.replace(1,3,str2);
cout << "str1=" << str1 << endl;
}
完整程序
#include<iostream>
#include<vector>
using namespace std;
//字符串的查找和替换
//1.查找
void test01()
{
string str1 = "abcdefde";
//find
int pos = str1.find("de");
if (pos == -1)
cout << "未找到" << endl;
else
cout << "pos=" << pos << endl;
//rfind
//rfind和find 区别
//find从左往右找;
//rfind从右往左找; 但是他们的pos还是按照从左往右的顺序的序号,下标从0开始
int rpos = str1.rfind("de");
if (rpos == -1)
cout << "未找到" << endl;
else
cout << "rpos=" << rpos << endl;
}
//替换
void test02()
{
string str1 = "abcdef";
string str2 = "123456";
//从1号位置起,3个字符“bcd”替换为字符串str2的"123456"
str1.replace(1,3,str2);
cout << "str1=" << str1 << endl;
}
int main()
{
test01();
test02();
return 0;
}