C++学习笔记(8)---STL、容器算法迭代器、string、vector

目录

1 STL---Standard Template Library---标准模板库

2  容器算法迭代器初识

3 string容器---本质为类

4 Vector容器---动态扩展的数组

长久以来,软件界一直希望建立一种可重复利用的东西

C++的面向对象泛型编程思想,目的就是复用性的提升;

为了建立数据结构和算法的一套标准,诞生了STL

1 STL---Standard Template Library---标准模板库

1.1 STL基本概念

(1)STL从广义上分为:容器(container)算法(algorithm)迭代器(iterator)

(2)容器算法之间通过迭代器进行无缝连接;

(3)STL几乎所有代码都采用了模板类或者模板函数;

1.2 STL六大组件

STL大体分为六大组件:分别是:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器

1、容器:各种数据结构,如vector,list,deque,set,map等,用来存放数据;

2、算法:各种常用算法:如sort,find,coopy,for_each等;

3、迭代器:扮演了容器和算法的胶合剂;

4、仿函数:行为类似函数,可作为算法的某种策略;

5、适配器:一种用来修饰容器或者仿函数或迭代器接口的东西;

6、空间适配器:负责空间的配置与管理。

1.3 STL中容器、算法、迭代器

1、容器:置物之所也

(1)STL容器是将运用最广泛的一些数据结构实现出来;

(2)常用的数据结构:数组、链表、树、栈、队列、集合、映射表等;

这些容器分为序列式容器关联式容器两种

序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置;

关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系;

2、算法:问题之解法也

(1)有限的步骤,解决逻辑或数学上的问题,这一门学科叫做算法(Algorithms)

(2)算法分为质变算法非质变算法

质变算法:是指运算过程中会更改区间内的元素的内容,例如拷贝、替换,删除等;

非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、计数、遍历、寻找极值等;

3、迭代器:容器和算法之间的粘合剂

提供一种方法,是指能够依序某个容器所含的各个元素,而又无需暴露该容器的内部表示方式;

每个容器都有自己专属的迭代器;迭代器使用非常类似于指针;

迭代器种类:常用的是双向迭代器随机访问迭代器

2  容器算法迭代器初识

STL最常用的容器为Vector,可以理解为数组

2.1 Vector存放内置数据类型

容器:vector;算法:for_each;迭代器:vector<int>::iterator

//-----------练习1:Vector遍历数据--------------------
void MyPrint(int val)
{
	cout<<val<<endl;
}
void test01()
{
	//创建vector容器对象,并且通过模板参数指定容器中存放数据的类型
	vector<int> v;//像一个类模板,创建对象
	//向容器中放数据
	v.push_back(10);//成员函数,尾插法
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);
	//每个容器都有自己的迭代器,迭代器是用来遍历容器中的元素
	//v.begin()返回迭代器,这个迭代器指向容器中的第一个数据
	//v.end()返回迭代器,这个迭代器指向容器的最后一个元素的下一次位置
	vector<int>::iterator pBegin=v.begin();
	vector<int>::iterator pEnd=v.end();
	//第一种遍历方式:
	while(pBegin != pEnd)
	{
		cout<<*pBegin<<endl;
		pBegin++;
	}
	//第二种遍历方式
	for(vector<int>::iterator it=v.begin();it!=v.end();it++)
	{
		cout<<*it<<endl;
	}
	//第三种遍历方式---使用STL提供标准遍历算法,头文件<algorithm>
	for_each(v.begin(),v.end(),MyPrint);
}

int main()
{
	test01();
	return 0;
}

2.2 Vector存放自定义数据类型

//--------------练习2: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()//存放Person
{
	//创建vector容器
	vector<Person> v;
	//创建数据
	Person P1("aaa",10);
	Person P2("bbb",10);
	Person P3("ccc",10);
	//存放数据---尾插法
	v.push_back(P1);
	v.push_back(P2);
	v.push_back(P3);
	//遍历数据,将It看做指针
	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;
	}
}
void test02()//存放Person*
{
	//创建vector容器
	vector<Person*> v;
	//创建数据
	Person P1("aaa",10);
	Person P2("bbb",10);
	Person P3("ccc",10);
	//存放数据---尾插法
	v.push_back(&P1);
	v.push_back(&P2);
	v.push_back(&P3);
	//遍历数据,将It看做指针
	for(vector<Person*>::iterator it=v.begin();it!=v.end();it++)
	{
		cout<<"姓名:"<<(*it)->m_Name<<" 年龄"<<(*it)->m_Age<<endl;
	}
}
int main()
{
	test02();
	return 0;
}

2.3 Vector容器嵌套容器,vector---一维数组

//-----------练习3:Vector容器嵌套容器,vector:一维数组--------
int main()
{
	//创建大容器
	vector<vector<int>> v;
	//创建小容器
	vector<int>v1;
	vector<int>v2;
	vector<int>v3;
	vector<int>v4;
	//向小容器中添加数据,尾插法
	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);
	}
	//向大容器中插入小容器
	v.push_back(v1);
	v.push_back(v2);
	v.push_back(v3);
	v.push_back(v4);
	//遍历数据
	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;
	}
	return 0;
}

3 string容器---本质为类

本质:string是C++风格的字符串,而string本质是一个类

string和char*区别:(1)char*是一个指针;

(2)string是一个类,类内部封装了char*,管理这个字符串,是一个char*型的容器;

特点:string类内部封装了很多成员函数,如find,copy,delete,replace,insert,

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

3.1 string构造函数

(1)string();//创建一个空的字符串,例如:string str;

(2)string(const char* s);//使用字符串S初始化

(3)string(const string& str);//使用一个string对象初始化另一个string对象

(4)string(int n,char c);//使用n个字符c初始化

void test01()
{
    string s1;//(1)默认构造,空
    const char* str="hello world";
    string s2(str);//(2)字符串初始化
    string s3(s2);//(3)拷贝
    string s4(10,'a');//(4)n个字符初始化
}

3.2 string赋值操作

//------------练习4:string字符串赋值----------------
void test()
{
	string str1="hello world";//(1)char*类型字符串=赋值
	cout<<str1<<endl;//hello world
	string str2=str1;//(2)字符串=赋值
	cout<<str2<<endl;//hello world
	string str3;
	str3='a';//(3)字符=赋值,重载=运算符
	cout<<str3<<endl;//a
	string str4;
	str4.assign("hello C++");//(4)assign字符串赋值
	cout<<str4<<endl;//hello C++
	string str5;
	str5.assign("hello C++",5);//(5)assign字符串前N个赋值
	cout<<str5<<endl;//hello
	string str6;
	str6.assign(str5);//(6)assign拷贝
	cout<<str6<<endl;//hello
	string str7;
	str7.assign(10,'b');//(7)assign中n个字符c赋值
	cout<<str7<<endl;//bbbbbbbbbb
}
int main()
{
	test();
	return 0;
}

 3.3 string字符串拼接---实现字符串末尾拼接字符串

 

str2.append(str2,4,3);//str2="LOL DNF";就将从第4个字符开始,截取3个字符,进行拼接

3.4 字符串的查找替换

查找:查找指定字符串是否存在;替换:在指定位置替换字符串

 总结:(1)返回-1就是找不到,否则返回位置坐标(默认int pos=0)

(2)rifnd是从右往左查找,find从左往右查找,都是查找返回第一次出现的位置

string str1="abcdefg";
//从1号位置起,3个字符替换为“111111”
str1.replace(1,3,"111111");
cout<<"str1="<<str1<<endl;//输出为“a111111efg”

3.5 字符串比较

字符串比较是按照非负的ASCII码进行对比,=0,str1>str2返回1,str1<str2返回-1

 

string str1="hello";
string str2="hello";
if(str1.compare(str2)==0){
    cout<<"str1等于str2"<<endl;
}

 总结:字符串对比主要是比较两个字符串是否相等,判断大小的意义并不大

3.6 string字符存取

 

//----------练习5:string字符存取----------------
void test()
{
	string str1="hello";
	//------------读取单个字符--------------
	//1、通过重载[]访问单个字符
	for(int i=0;i < str1.size();i++)//size()成员函数,计算字符串长度
	{
		cout<<str1[i]<<endl;
	}
	//2、通过at成员函数来访问单个字符
	for(int i=0;i < str1.size();i++)
	{
		cout<<str1.at(i)<<endl;
	}
	//---------------修改单个字符------------
	str1[0]='a';
	str1.at(1)='b';
	cout<<str1<<endl;//输出为abllo
}
int main()
{
	test();
	return 0;
}

3.7 string插入和删除

string str="hello";
str.insert(1,"111");//插入结果为:h111ello
str.erase(1,3);//删除,从第1个位置处删除3个字符,结果为hello

总结:插入和删除的起始位置下标都是从0开始;

3.8 string子串---从字符串中获取想要的子串

//------------练习6:string字符串截取子串--------
void test01()
{
	string str="abcdef";
	string subStr=str.substr(1,3);
	cout<<"subStr="<<subStr<<endl;
}
//实用操作,获取邮箱用户名
void test02()
{
	string email="Tom@sina.com";
	int pos=email.find('@');//pos=3
	string usrName=email.substr(0,pos);
	cout<<usrName<<endl;
}
int main()
{
	test02();
	return 0;
}

4 Vector容器---动态扩展的数组

4.1 vector基本概念

功能:vector数据结构和数组非常相似,也称为单端数组;

vecotor与普通数组区别:不同之处在于数组是静态空间,而vector可以动态扩展

动态扩展:

并不是在原空间之后续接新空间,而找更大的内存空间,然后将原数据拷贝新空间,释放原空间;

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

 4.2 vector构造函数---创建vector容器

//-----------练习7:vector构造函数------------
void MyPrint(vector<int>& v)
{
	for(vector<int>::iterator it=v.begin();it!=v.end();it++){
		cout<<*it<<" ";}
	cout<<endl;
}
void test()
{
	vector<int>v1;//默认构造,无参构造
	for(int i=0;i<10;i++)
	{
		v1.push_back(i);
	}
	MyPrint(v1);//输出为0 1 2 3 4 5 6 7 8 9
	vector<int>v2(v1.begin(),v1.end());//通过区间方式拷贝构造
	MyPrint(v2);//输出为0 1 2 3 4 5 6 7 8 9
	vector<int>v3(10,20);//n个元素构造
	MyPrint(v3);//输出为20 20 20 20 20 20 20 20 20 20
	vector<int>v4(v3);//拷贝构造函数
	MyPrint(v4);//输出为20 20 20 20 20 20 20 20 20 20
}
int main()
{
	test();
	return 0;
}

 4.3 vector容器-赋值操作

 总结:(1)assign中,区间为前闭后开;(2)注意构造和赋值,赋值是构造之后,进行赋值

 4.4 vector容器-容量和大小

//------------练习8:vector的容量和大小-----------
void MyPrint(vector<int>&v)
{
	for(vector<int>::iterator it=v.begin();it!=v.end();it++)
		cout<<*it<<" ";
	cout<<endl;
}
void test()
{
	vector<int>v1;
	for(int i=0;i<10;i++)
	{
		v1.push_back(i);//尾插法填充数据
	}
	if(v1.empty()){//返回1为空
		cout<<"空"<<endl;}
	else{
		cout<<"非空"<<endl;}
	cout<<"vector容量:"<<v1.capacity()<<endl;//13---动态拓展
	cout<<"vector大小:"<<v1.size()<<endl;//10
	MyPrint(v1);//0 1 2 3 4 5 6 7 8 9
	v1.resize(15);//默认填充0
	MyPrint(v1);//0 1 2 3 4 5 6 7 8 9 0 0 0 0 0
	v1.resize(20,8);//指定填充
	MyPrint(v1);//0 1 2 3 4 5 6 7 8 9 0 0 0 0 0 8 8 8 8 8
}
int main()
{
	test();
	return 0;
}

 4.5 vector容器-插入和删除

//------------练习9:vector的插入和删除----------
void MyPrint(vector<int>& v)
{
	for(vector<int>::iterator it=v.begin();it!=v.end();it++)
		cout<<*it<<" ";
	cout<<endl;
}
void test()
{
	vector<int> v1;
	for(int i=0;i<5;i++)
	{
		v1.push_back(i);//尾插法填充数据
	}
	MyPrint(v1);//0 1 2 3 4
	v1.pop_back();//删除最后一个元素
	MyPrint(v1);//0 1 2 3
	v1.insert(v1.begin(),10);//插入一个数据
	MyPrint(v1);//10 0 1 2 3
	v1.insert(v1.begin(),2,100);//输入n个元素
	MyPrint(v1);//100 100 10 0 1 2 3
	v1.erase(v1.begin());//删除迭代器指向的元素
	MyPrint(v1);//100 10 0 1 2 3
	v1.erase(v1.begin(),v1.end());//删除迭代器区间内的元素
	MyPrint(v1);
	v1.clear();//删除容器中的所有元素
	MyPrint(v1);
}
int main()
{
	test();
	return 0;
}

4.6 vector容器-数据存取

 

 

 总结:可以[]方式访问数组中元素

4.7 vector容器-互换容器---实现两个容器内元素进行互换

//利用swap收缩空间,v1容量10万,占3
vector<int>(v1).swap(v1);//vector<int>(v1)利用拷贝创建匿名对象,swap();交换

总结:swap可以使两个容器互换,可以达到实用的收缩内存效果;

 4.8 vector容器-预留空间---减少vector在动态扩展容量时的扩展次数

//------------练习10:vector容器-预留空间-------
void test()
{
	vector<int>v1;
	//利用reserve预留空间
	v1.reserve(10000);
	int num=0;//统计动态扩展开辟内存次数
	int* p=NULL;
	for(int i=0;i<10000;i++)
	{
		v1.push_back(i);
		if(p!=&v1[0])
		{
			p=&v1[0];
			num++;
		}
	}
	cout<<"num="<<num<<endl;//24次放10000个,reverse之后,num=1
}
int main()
{
	test();
	return 0;
}

 总结:如果数据量级很大,可以提前预留空间,减少动态扩展的次数

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值