C++容器
C++中STL的容器,包括容器的概念,顺序容器、关联容器、映射map和set容器。最后还有跟着动手编写程序,加深印象。
C++容器
容器的概念
C++中容器的定义如下:数据存储上,有一种对象类型,它可以持有其他对象或指向其他对象的指针,这种对象类型叫容器。容器类是一种对特定代码重用问题的良好的解决方案。容器另一个好处就是可以自行扩展,解决问题时通常不知道需要存储多少个对象,数组在这方面也是力不从心。容器可以申请内存、释放内存,并且使用最优的算法来执行命令。
顺序容器
向量(vector)
vector是一个动态的顺序容器,具有连续内存地址的数据结构,通过下标运算符“[ ]”直接有效地访问向量的任何元素。相比于数组,vector会消耗更多的内存以有效地动态增长。而相比于其他序列容器(deques,lists),vector能更快地索引元素(就像数组一样),而且能相对高效地在尾部插入和删除元素。
注意:当需要使用vector的时候,需要包含头文件:#include ,一般加上“using namespace std;”,如果不加,则在调用时候必须用std::vector<…>这样的形式,即在vector前加上std::,这表示运用的是std命名空间下的vector容器。
编写程序,对一个大小为10的向量容器进行修改和访问。
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> a(10, 1); //大小为10,初始值为1的向量a
int i;
cout << "初始化变量";
for ( i = 0; i < a.size(); i++)
{
cout << a[i] << " ";
}
cout << "\n插入数据:";
cin >> a[2];
cin >> a[5];
cin >> a[8];
cout << "赋值后遍历:";
for (i = 0; i < a.size(); i++)
{
cout << a[i] << " ";
}
cout << endl;
return 0;
}
二维向量,与数组相同,向量也可以增加维数。
例如,声明一个m*n大小的二维向量方式可以像如下形式:
vector< vector<int> > a(3,vector<int>(4)); //相当于a[3][4]
编写程序,实现vector的基本操作。
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int i = 0;
vector<int>a;
for ( i = 0; i < 10; i++)
{
a.push_back(i); //10个元素依次进入数组
}
cout << "初始化遍历:";
for (i = 0; i < a.size(); i++)
{
cout << a[i] << " ";
}
cout << "\n迭代 遍历:";
vector<int>::iterator it; //迭代器进行访问
for (it = a.begin(); it != a.end(); it++)
{
cout << *it << " ";
}
cout << "\n插入 遍历:";
a.insert(a.begin() + 4, 0); //在第5个元素之前加0
for (unsigned int i = 0; i < a.size(); i++)
{
cout << a[i] << " ";
}
cout << "\n擦除 遍历:";
a.erase(a.begin() + 2);
for (unsigned int i = 0; i < a.size(); i++)
{
cout << a[i] << " ";
}
cout << "\n迭代 遍历:";
a.erase(a.begin() + 3, a.begin() + 5);
for (vector<int>::iterator it = a.begin(); it != a.end(); it++)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
列表
list是STL实现的双向链表,相对于vector的连续线性空间,list就显得复杂太多,它允许快速地插入和删除,但是随机访问却比较慢。它的数据由若干个节点构成,每一个节点都包括一个信息块、一个前驱指针和一个后驱指针,可以向前也可以向后进行访问,但不能随机访问。它的好处是每次插入或者删除就会配置或者释放一个元素空间,而且它对于空间的运用绝对精准,一点也不多余。列表的定义在头文件“#include ”中。
编写程序,创建一个list实例并赋值。
#include<iostream>
#include<list>
using namespace std;
int main()
{
list<int>lst;
for (int i = 0; i <= 5; i++)
{
lst.push_back(i);
}
cout << "在元素末尾操作数据:" << endl;
lst.push_back(999);
for (list<int>::iterator it = lst.begin(); it != lst.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
lst.pop_back();
for (list<int>::iterator it = lst.begin(); it != lst.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
cout << "在元素开头操作数据:" << endl;
lst.push_front(888);
for (list<int>::iterator it = lst.begin(); it != lst.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
【程序小结】本例中使用push_back()函数在列表容器的末尾插入数据,push_front()函数是在列表开头插入数据。
编写程序,对列表容器进行顺序遍历和逆序遍历。
#include<iostream>
#include<list>
using namespace std;
int main()
{
int a[5] = { 22,33,44,55,66 };
list<int> lst(a, a + 5); //将数组a的前5个元素作为列表容器lst的初值
cout << "正序输出:";
for (list<int>::iterator it = lst.begin(); it != lst.end(); ++it)
{
cout << " " << *it;
}
cout << '\n';
lst.clear();
cout << "逆序输出:";
for (int i = 1; i <= 5; ++i)
{
lst.push_back(i);
}
for (list<int>::reverse_iterator rit = lst.rbegin(); rit != lst.rend(); ++rit)
{
cout << ' ' << *rit;
}
cout << endl;
return 0;
}
【程序小结】先定义了一个数组a并赋初值。然后将数组a的前5个元素作为列表容器的初值,再定义迭代器指针,从列表头开始依次遍历。接着,再使用迭代器从列表的尾部依次遍历。
关联容器
关联容器主要有映射(map)和集合(set),支持通过键来高效地查找和读取元素。map的元素以键-值对(key-value)的形式组织:键用作元素在map类型下进行索引,而值则表示所存储和读取的数据。set仅包含一个键,并有效地支持关于某个键是否存在的查询。set和map类型的对象不允许为同一个键添加第二个元素。如果一个键必须对应多个实例,则需使用多重映射(multimap)或多重集合(mutiset)类型,这两种类型允许多个元素拥有相同的键。
映射map
映射map就是标准模板库中的一个关联容器,它提供一对一的数据处理能力。map的元素是由key和value两个分量组成的对偶(key,value)。元素的键key是唯一的,给定一个key,就能唯一地确定与其相关联的另一个分量value。
编写程序,遍历map容器。
#include<iostream>
#include<string>
#include<map>
using namespace std;
int main()
{
cout << "正序输出:\n";
map<int, string>M;
M.insert(pair<int, string>(1, "M_first"));
M.insert(pair<int, string>(2, "M_second"));
M.insert(pair<int, string>(3, "M_third"));
map<int, string>::iterator iter;
for (iter = M.begin(); iter != M.end(); iter++)
{
cout << iter->first << " " << iter->second << endl;
}
cout << endl;
return 0;
}
cout << "\n逆序输出:";
map<int, string>::reverse_iterator iter;
for (iter = M.rbegin(); iter != M.rend(); iter++)
{
cout << iter->first << " " << iter->second << endl;
}
set类容器
set的使用
使用set之前必须包含set头文件,set支持的操作基本与map提供的相同。
verctor<int> ivec;
for(verctor<int>::size_type i=0;i!=10;++i)
{
ivec.push_back(i);
ivec.push_back(i);
}
//用ivec初始化set
set<int> iset(ivec.begin(),ivec.end());
cout<<ivec.size()<<endl; //输出20
cout<<iset.size()<<endl; //输出10
set中添加元素
直接插入
set<string> set1;
set1.insert("the");
使用迭代器
set<string> set2;
set2.insert(Iveco。begin(),ivec.end());
从set中获取元素
set没有下标操作,为了通过键从set中获取元素,可使用find()运算。如果仅是判断某个元素是否存在,也可使用count()操作,返回值只能是1或0。
容器适配器
容器适配器有三种:stack、queue和priority_queue。stack可以与数据结构中的栈对应,它具有先进后出的特性,而queue则可以理解为队列,它具有先进先出的特性,priority_queue则是带优先级的队列,其元素可以按照某种优先级顺序进行删除。
综合应用
编写程序,使用向量容器,根据年龄的大小,对5位青少年进行排序。
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
struct Person
{
char name[10];
int age;
};
bool comp(const Person& a, const Person& b)
{
return a.age < b.age; //自定义 小于
}
int main()
{
vector<Person> v_per;
int n = 5;
while (n--)
{
Person people;
string name;
int age;
cin >> name >> age;
strcpy_s(people.name, name.c_str());
people.age = age;
v_per.push_back(people);
}
cout << "-----------------排序前---------------" << endl;
for (vector<Person>::iterator it = v_per.begin(); it != v_per.end(); it++)
{
cout << "姓名:" << it->name << "\t年龄:" << it->age << endl;
}
sort(v_per.begin(), v_per.end(), comp);
cout << "-----------------排序后---------------" << endl;
for (vector<Person>::iterator it = v_per.begin(); it != v_per.end(); it++)
{
cout << "姓名:" << it->name << "\t年龄:" << it->age << endl;
}
cout << endl;
return 0;
}
【程序小结】本例中先定一个关于人的结构体,该结构体例有两个成员,分别表示一个人的姓名和年龄。再定义一个bool型的比较函数comp(),并返回两个年龄之间的比较。在main()函数中,定义一个向量对象v_per。然后通过while循环,依次输入5个人的年龄和姓名。最后定义迭代器,依次将该容器遍历出来。
面试常见问题
如何选取合适的容器?
答:如果用户需要高效的随机存取,而不在乎插入和删除的效率,使用vector;如果用户需要大量的插入和删除,而不关心随机存取,则应使用list;如果用户需要随机存取,而且关心两端数据的插入和删除,则应使用deque。
更多推荐
所有评论(0)