一.vector---数组
1.vector的初始化
相对于string,vector的设计更加简洁和精干,以下是3种常见的初始化方式:
int main()
{
//1.用n个a元素初始化
//vector<类型名> 变量名(n,a);
vector<int> v1(10, 1);
//2.用迭代器区间初始化
//vector<类型名> 变量名(开始迭代器,结束迭代器);
vector<int>::iterator it1 = v1.begin();
vector<int>::iterator it2 = v1.end();
vector<int> v2(it1,it2);
//当然,某些类型就是用原生指针充当迭代器,因此也可以用指针来初始化
int a[5] = { 1,2,3,4,5 };
vector<int> v3(a, a + 5);
//3.直接用拷贝构造来初始化
vector<int> v4 = v3;
cout << "v1:";
for (auto i : v1)
{
cout << i << " ";
}
cout << endl;
cout << "v2:";
for (auto i : v2)
{
cout << i << " ";
}
cout << endl;
cout << "v3:";
for (auto i : v3)
{
cout << i << " ";
}
cout << endl;
cout << "v4:";
for (auto i : v4)
{
cout << i << " ";
}
cout << endl;
return 0;
}
2.vector的增删查改
int main()
{
vector<int> v1(10, 1);
//1.可以使用下标来查看vector的各个元素
//使用v1.size()获取v1的元素个数,同样,使用v1.capacity()获取其容量大小
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
//使用front和back获取数组首尾元素
v1.front() = 2;
v1.back() = 3;
cout <<"v1首元素:" << v1.front()<<endl;
cout << "v1尾元素:" << v1.back()<<endl;
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
//使用 变量名.push_back(要添加的元素) 向数组尾部添加元素
v1.push_back(4);
cout <<"v1尾部:" << v1[v1.size() - 1] << endl;
//使用 变量名.insert(迭代器,要添加的元素) 向指定迭代器位置添加元素
v1.insert(v1.begin()+2,10);
cout << "向指定位置插入元素后:";
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
//使用 变量名.pop_back() 删除尾部元素
v1.pop_back();
cout << "删除尾部元素后:";
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
//使用 变量名.erase(迭代器) 删除指定迭代器位置的元素
v1.erase(v1.begin()+2);
cout << "向指定位置插入元素后:";
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
//使用 变量名.clear() 清空数组
v1.clear();
cout << "清空后:";
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
return 0;
}
二.list---链表
1.vector与list迭代器的区别与两个容器的优劣
vector迭代器使用的是随机迭代器,允许进行++, -- , + , - , += , -= ,= 操作,且因为是随机迭代器,vector对象本身支持[]下标访问,而list使用的是单向迭代器,仅允许++,-- ,=操作,list对象本身不支持[]下标访问。
就插入和删除而言,由于list并不像vector存在频繁挪动数据和整体性扩容,因此效率要高于vector,而就对容器内元素的访问而言,list无法直接用下标进行访问,效率要低于vector。
2.list的初始化
template<class T>
void printItems(T items)
{
for (auto i : items)
{
cout << i << " ";
}
cout << endl;
}
int main()
{
//1.使用n个a元素初始化
//list<类型名> 变量名(n,a)
list<int> l1(10,1);
//2.使用迭代器初始化
list<int> l2(l1.begin(), l1.end());
//不一定要是list的迭代器哟~
vector<int> v1(10, 1);
list<int> l3(v1.begin(), v1.end());
//当然,你也可以直接用原始数组
int a[5] = { 1,2,3,4,5 };
list<int> l4(a, a + 5);
//3.直接拷贝构造
list<int> l5 = l4;
cout << "l1:";
printItems(l1);
cout << "l2:";
printItems(l2);
cout << "l3:";
printItems(l3);
cout << "l4:";
printItems(l4);
cout << "l5:";
printItems(l5);
}
3.list的增删查改
template<class T>
void printItems(T items)
{
for (auto i : items)
{
cout << i << " ";
}
cout << endl;
}
int main()
{
list<int> l1(10, 1);
cout << "l1:";
printItems(l1);
//使用front(),back()获取链表首尾元素
l1.front() = 2;
l1.back() = 3;
cout << "改变首尾元素后:";
printItems(l1);
//由于无法使用下表访问元素,要访问中间位置的元素,我们直接对迭代器进行操作
list<int>::iterator it = l1.begin();
for (int i = 0; i < 2; i++)
{
it++;
}
*it = 4;
cout << "改变中间元素后:";
printItems(l1);
//使用 变量名.push_front(元素) 和 变量名.push_back(元素) 向链表首尾添加元素
l1.push_front(6);
l1.push_back(7);
cout << "向首尾插入元素后:";
printItems(l1);
//使用 变量名.insert(迭代器,要添加的元素) 向指定迭代器位置添加元素
l1.insert(++l1.begin(),8);
cout << "向指定位置插入元素后:";
printItems(l1);
//使用 变量名.pop_back() 和 变量名.pop_back() 删除首尾元素
l1.pop_front();
l1.pop_back();
cout << "删除首尾元素后:";
printItems(l1);
//使用 变量名.erase(迭代器) 删除指定迭代器位置的元素
l1.erase(++l1.begin());
cout << "删除指定位置元素后:";
printItems(l1);
//使用 变量名.clear() 清空链表
l1.clear();
cout << "清空后:";
printItems(l1);
return 0;
}
三.迭代器失效问题
在使用含有迭代器的容器时,我们可能一不小心就触发了迭代器的失效
int main()
{
vector<int> v1(3, 2);
vector<int>::iterator it = v1.begin();
cout << *it << endl;
v1.push_back(3);
cout << *it << endl;
return 0;
}
如图,*it在第二次并未像我们预想的一样将2打印出来,原因就在于it这个迭代器失效了,正如其字面意思,迭代器失效,就是迭代器失去了原来的效果,无法被继续使用了
迭代器失效有两种原因,第一种是迭代器所指向的原有空间所含内容被删除或转移,形成了野指针,我们所举的例子就属于这种,最开始初始化时我们为其分配了3个元素的空间,但后面又追加了一个元素,原有空间不够,数组扩容,原有内容被转移,it迭代器自然也就失效了
还有一种原因,就是原有迭代器含义变了
int main()
{
vector<int> v1(6, 2);
vector<int>::iterator it = v1.begin();
cout << *it << endl;
while (it != v1.end())
{
v1.erase(it);
it++;
}
cout << v1.size() << endl;
return 0;
}
我们想用while循环来清空v1,但在删除it的内容后,it指向该内容的下一个,而it仍要++,跳过了该内容的下一个,无法完成任务
想要避免这种情况,需要将it删除后的结果重新赋值给it以代替++,删除后其本身就已经指向下一个了
修改后如下:
int main()
{
vector<int> v1(6, 2);
vector<int>::iterator it = v1.begin();
cout << *it << endl;
while (it != v1.end())
{
it = v1.erase(it);
}
cout << v1.size() << endl;
return 0;
}