目录
一、stcak容器(栈容器)
1、基本概念
2、常用接口
二、queue容器(队列容器)
1、基本概念
2、常用接口函数
三、list容器(链表)
1、基本概念
2、构造函数
3、赋值与交换
4、大小操作
5、插入与删除
6、数据存取
7、反转和排序
8、排序的案例
四、set/multiset容器
1、基本概念
2、构造函数
3、大小与交换操作
4、插入和删除操作
5、查找和统计操作
6、set/multiset区别
7、pair对组创建
8、排序
五、map/multimap容器
1、基本概念
2、构造函数与赋值
3、大小和交换操作
4、插入和删除操作
5、查找和统计操作
6、排序
六、案例-员工分组
具体实现:
/*
1、构造函数
stack stk; stack采用模板类实现,stack对象的默认构造
stack(const stack& stk); 拷贝构造
2、赋值操作
stack& operator=(const stack & stk); 重载=运算符
3、数据存取
stk.push(elem); 向栈顶添加元素
stk.pop(); 删除栈顶元素
stk.top(); 返回栈顶元素
4、大小操作
stk.empty(); 判断堆栈是否为空
stk.size(); 返回栈的大小
*/
void test01()
{
stack s; // 创建栈容器s
s.push(1);
s.push(2);// 插入元素
s.push(3);
s.push(4);
cout << s.size() << endl; // 查看大小
cout << s.empty() << endl;// 判断是否为空,不为空返回0
while (!s.empty()) // 不为空执行循环
{
cout << s.top(); // 输出栈顶元素
s.pop(); // 出栈
}
cout << endl;
cout << s.size() << endl; // 查看大小
cout << s.empty() << endl;// 判断是否为空,为空返回1
}
/* queue容器
1、构造函数
queue que; queue采用模板类实现,queue对象的默认构造
queue(const queue& que); 拷贝构造
2、赋值操作
queue& operator=(const queue & que); 重载=运算符
3、数据存取
que.push(elem); 向队尾添加元素
que.pop(); 删除队头元素
que.front(); 返回队头元素
que.back(); 返回队尾元素
4、大小操作
que.empty(); 判断堆栈是否为空
que.size(); 返回队列的大小
*/
这里我使用自定义数据类型person
class person
{
public:
person(string name,int age)
{
this->m_name = name;
this->m_age = age;
}
string m_name;
int m_age;
};
void test02()
{
queue q;// 创建queue容器q
// 先创建几个person类型对象
person p1("Joyce", 21);
person p2("Tatina", 20);
person p3("Yomi", 2);
person p4("Nna", 15);
// 插入到容器q中 入队
q.push(p1);
q.push(p2);
q.push(p3);
q.push(p4);
// 打印p中的数据
cout << q.size() << endl; // 查看大小
cout << q.empty() << endl;// 判断是否为空,不为空返回0
while (!q.empty()) // 不为空执行循环
{
cout << "头"<
同时含有很多迭代器:push_front()、push_back()、pop_front()、pop_back()等
由于链表的存储方式不是连续的内存空间,因此链表中的迭代器只支持前移--和后移++,不可以+*好几个数,属于双向迭代器
链表优点:
①采用动态内存分配,不会造成内存浪费与溢出
②链表插入与删除操作非常方便,修改指针即可,不需要移动大量元素
缺点:
灵活但空间(指针域)和时间(遍历)额外耗费大
/*构造函数
list lst; 1使用模板类实现,默认构造
list(begin,end); 2将区间[begin,end)中的元素拷贝给自身,注意区间左闭右开
list(n,elem); 3将n个elem元素拷贝给自身
list(const list& lst); 4将lst拷贝给自身,拷贝构造函数
*/
void test03()
{
list l1;// 1创建容器
l1.push_back(1);// 插入元素
l1.push_back(2);
l1.push_back(3);
l1.push_back(4);
printl(l1); // 打印函数
list l2(l1.begin(), l1.end()); // 2
printl(l2);
list l3(5, 888); // 3
printl(l3);
list l4(l1); // 4
printl(l4);
}
其中,我实现了一个打印函数(下面所有打印数据都用这个函数,每一行数据代表一次调用)
void printl(const list& l) // 打印函数
{
for (list::const_iterator it = l.begin(); it != l.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
和vector容器创建容器方法基本相同
/*赋值与交换
list operator=(const list& lst); 重载=运算符
lst.assign(begin,end); 将区间[begin,end)中的数据拷贝给自身,注意区间左闭右开
lst.assign(n,elem); 将n个elem元素拷贝给自身
lst.swap(lst1); 将lst1的元素与自身交换
*/
/*容量和大小
lst.empty(); 1判断容器是否为空,空返回true1否则false0
lst.size(); 2返回容器当前大小
lst.resize(int n); 3重新指定容器长度为n,若容器变长,则以默认值0填充新位置。
若容器变短,则末尾超出容器长度的元素被删除
lst.resize(int n,elem); 4重新指定容器长度为n,若容器变长,则以elem填充新位置。
若容器变短,则末尾超出容器长度的元素被删除
*/
/*插入与删除
lst.push_front(elem); 1头部插入elem元素
lst.pop_front(); 2删除头部第一个元素
lst.push_back(elem); 3尾部插入elem元素
lst.pop_back(); 4删除尾部最后一个元素
lst.insert(const_iterator pos,elem); 5在迭代器指向的pos位置插入元素elem
lst.insert(const_iterator pos,int n,elem); 6在迭代器指向的pos位置插入n个elem元素
lst.insert(const_iterator pos,const_iterator start,const_iterator end);
7在迭代器指向的pos位置插入从start到end区间的元素
lst.erase(const_iterator pos); 8删除迭代器指向的pos位置的元素
lst.erase(const_iterator start,const_iterator end); 9删除迭代器指向的从start到end区间的元素
lst.clear(); 10删除容器中所有元素
lst.remove(elem); 11删除容器中所有与elem值匹配的元素
*/
void test06()
{
list l1;// 创建容器
l1.push_back(1);// 3尾插
l1.push_back(2);
l1.push_back(3);
l1.push_back(4);
printl(l1);
l1.push_front(40); // 1头插
l1.push_front(30);
l1.push_front(20);
l1.push_front(10);
printl(l1);
l1.pop_back(); // 4尾删
l1.pop_back();
printl(l1);
l1.pop_front(); // 2头删
l1.pop_front();
printl(l1);
l1.insert(l1.begin(), 888); // 5 插入指定元素
printl(l1);
l1.insert(l1.begin(), 8, 66); // 6 插入指定个数元素
printl(l1);
l1.insert(l1.begin(),l1.begin(),l1.end()); // 7 头部插入区间元素
printl(l1);
l1.erase(l1.begin()); // 8 删除指定位置元素
printl(l1);
list l2 = l1;
printl(l2);
l2.erase(++l2.begin(), --l2.end()); // 9 删除指定区间元素
printl(l2);
l1.remove(66); // 11 删除容器中指定的所有元素
printl(l1);
l1.clear();
printl(l1); // 10 清空容器
}
一行数据对应一个printl,上面挡住了第一个prinl
/*数据存取
lst.front(); 返回队头元素
lst.back(); 返回队尾元素
*/
首先:
void test07()
{
list l1;// 创建容器
l1.push_back(1);// 3尾插
l1.push_back(2);
l1.push_back(3);
l1.push_back(4);
printl(l1);
cout << l1.front() << endl;
cout << l1.back() << endl;
cout << ++l1.front() << endl; // 只能前移或后移
cout << l1.back()-- << endl;
}
/*反转与排序
lst.reverse(); 反转链表
lst.sort(); 排序链表
*/
void test08()
{
list l1;// 创建容器
l1.push_back(1);// 3尾插
l1.push_back(9);
l1.push_back(8);
l1.push_back(7);
printl(l1);
l1.reverse(); // 反转
printl(l1);
l1.sort(); // 排序
printl(l1);
}
注意:所有不支持随机访问迭代器的容器,不可以用标准算法
,而容器内部会提供一些对应的算法
首先自己实现仿函数
bool my_compare(int x, int y)
{
return x > y;
}
调用sort重载
l1.sort(my_compare); // 降序
printl(l1);
void test09()
{
list l; // 创建容器
// 根据自定义数据类型创建对象
person p1("Joyce", 21, 180);
person p2("Tatina", 20, 162);
person p3("Yomi", 2, 30);
person p4("Nana", 20, 180);
// 插入进容器
l.push_back(p1);
l.push_back(p2);
l.push_back(p3);
l.push_back(p4);
printp(l); // 打印查看
l.sort(my_compare);
printp(l); // 打印查看
}
打印函数printp
void printp(const list&p)
{
for (list::const_iterator it = p.begin(); it != p.end(); it++)
{
cout << "姓名" << (*it).m_name << "年龄" << (*it).m_age << "身高" << (*it).m_height << endl;
}
cout << endl;
}
排序函数sort();我们加上仿函数 使其重载(指定排序规则)
bool my_compare(person &p1,person& p2) // 仿函数
{
if (p1.m_age == p2.m_age) // 年龄相同
{
return p1.m_height < p2.m_height;// 按照身高升序
}
else
{
return p1.m_age < p2.m_age;// 按照年龄升序
}
}
成功以年龄和身高排序
ps:在所有代码之前,我先实现一个打印函数,以便后面打印输出容器中的数据
void prints(set st)
{
for (set::iterator it = st.begin(); it != st.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
/*构造函数
set st; 1默认构造函数
set(const set &st); 2拷贝构造函数
set& operator=(const set& st); 3重载=运算符
*/
测试:
void test01()
{
set st1; // 1
st1.insert(1);
st1.insert(8);
st1.insert(6);
st1.insert(3);
st1.insert(8); // 重复的8,无法插入
prints(st1);
setst2(st1); // 2
prints(st2);
setst3;
st3 = st1; // 3
prints(st3);
}
可见,set容器无法插入相同元素
首先,由于set容器不允许有重复的元素,因此它没有指定容器大小的函数
/*大小与交换
st.size(); 返回容器中元素的个数
st.empty(); 判断容器是否为空,空返回1,否则返回0
st.swap(st1); 交换2个容器
*/
测试:
void test02()
{
set st1;
cout << st1.size() << endl;
cout << st1.empty() << endl;
st1.insert(1);
st1.insert(8);
st1.insert(6);
st1.insert(3);
cout << st1.size() << endl;
cout << st1.empty() << endl;
set st2;
st2.insert(88); st2.insert(66);
st2.insert(54); st2.insert(13);
cout << "交换前" << endl;
prints(st1);
prints(st2);
st2.swap(st1);
cout << "交换后" << endl;
prints(st1);
prints(st2);
}
/*插入和删除
st.insert(); 1插入元素
st.clear(); 2清空容器
st.erase(pos); 3删除迭代器pos处的元素
st.erase(begin,end);4删除迭代器区间begin,end之间的元素
st.erase(elem); 5删除elem元素
*/
测试:
void test03()
{
set st1;
st1.insert(1); // 1
st1.insert(8);
st1.insert(6);
st1.insert(3);
st1.insert(5);
st1.insert(9);
prints(st1);
st1.erase(++st1.begin());// 3
prints(st1);
st1.erase(++st1.begin(), --st1.end());// 4
prints(st1);
st1.erase(1);
prints(st1); // 5
st1.clear(); // 2
prints(st1);
}
/* 查找与统计
st.find(val); 查找val元素是否存在,存在返回其位置的迭代器,否则返回st.end();
st.count(val); 统计元素val的个数
*/
由于set容器中没有重复元素,因此count只有0/1
测试:
void test04()
{
set st1;
st1.insert(1);
st1.insert(8);
st1.insert(6);
st1.insert(3);
set ::iterator pos = st1.find(3);
if (pos == st1.end())
cout << "没找到" << endl;
else
cout << "有了" << endl;
cout << st1.count(3) << endl;
}
①set不可以重复插入,multiset可以
②set插入数据的同时会返回插入结果,表示是否成功
③multiset不会检测数据,因此可以重复插入相同元素
因为set的insert是对组pair,有两个数据:iterator代表返回的位置,bool代表是否插入成功
我们创建容器,尝试插入1个与2个相同数据,并通过返回值的第二个数据bool值判断是否成功
void test05()
{
set s;
pair::iterator,bool> ret = s.insert(5);
if (ret.second)
cout << "插入成功" << endl;
else
cout << "插入失败" << endl;
ret = s.insert(5);
if (ret.second)
cout << "插入成功" << endl;
else
cout << "插入失败" << endl;
}
由此可见,第一次成功,第二次失败。
而相对的,multiset的insert就只有一个iterator代表插入后返回的位置
因此,它可以重复插入相同元素
multisetms;
ms.insert(5);
ms.insert(5);
ms.insert(5);
ms.insert(5);
for (multiset::iterator it = ms.begin(); it != ms.end(); it++)
cout << *it << " ";
对组:成对出现的数据,利用对组可以返回2个数据
/*对组的创建
pair p(val1,val2);
pair p=make_pair(val1,val2);
*/
测试:
void test06()
{
pairp1("Joyce", 21);
cout << p1.first <<"年"<< p1.second << endl;
pairp2 = make_pair("Tatina", 20);
cout << p2.first << "年" << p2.second << endl;
}
注意:应在插入数据前就指定其排序规则,否则都插入了无法排序
①内置数据类型排序
void test07()
{
set st1;
st1.insert(1); st1.insert(8); st1.insert(6);
st1.insert(3); st1.insert(5); st1.insert(9);
prints(st1);
// 进行降序排列
set st2;
st2.insert(1); st2.insert(8); st2.insert(6);
st2.insert(3); st2.insert(5); st2.insert(9);
for (set::iterator it = st2.begin(); it != st2.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
加上仿函数:
class MYcompare
{
public:
bool operator()(int x, int y)const
{
return x > y;
}
};
②自定义数据类型
对于自定义数据类型,容器中没有可以直接排序的算法,因此我们需要在插入数据前就指定排序规则
自定义数据类型person
class person
{
public:
person(string name, int age)
{
this->m_name = name;
this->m_age = age;
}
string m_name;
int m_age;
};
仿函数
class mycompareperson
{
public:
bool operator()(const person &p1, const person &p2)const
{ // 升序
return p1.m_age < p2.m_age;
}
};
测试:
void test08()
{
set s1;
person p1("Joyce", 21);
person p2("Tatina", 20);
person p3("Naba", 30);
person p4("Knaz", 40);
s1.insert(p1); s1.insert(p2);
s1.insert(p3); s1.insert(p4);
for (set::iterator it = s1.begin(); it != s1.end(); it++)
cout << it->m_name << "年龄为" << it->m_age << endl;
}
int ma
已经按照年龄升序排列
①map中所有元素都是pair
②pair中第一个数据是key(键值,起到索引作用),第二个数据是val(实际存储的值)
③所有元素都会根据元素的键值自动排序
①map不允许有重复key值存在,但可以有重复val值
②multimap允许有重复key值
首先,我先实现一个打印函数,以便下面容器中数据的打印查看,对组中两个数据均为int
void printm(map mp)
{
for (map::iterator it = mp.begin(); it != mp.end(); it++)
{
cout << it->second << " ";
}
cout << endl;
}
作用:对map容器进行构造与赋值操作
/*构造与赋值
map mp; 默认构造函数
map(const map& mp); 拷贝构造函数
map& operator=(const map &mp);重载=运算符
*/
测试:
void test01()
{
map mp1; // 1
mp1.insert(pair(1, 11));
mp1.insert(pair(2, 22));
mp1.insert(pair(4, 44));
mp1.insert(pair(3, 33));
printm(mp1);
map mp2(mp1); // 2
printm(mp2);
map mp3 = mp1; // 3
printm(mp3);
}
首先,由于map容器不允许有重复的元素,因此它没有指定容器大小的函数
/*大小与交换
mp.size(); 返回容器中元素的个数
mp.empty(); 判断容器是否为空,空返回1,否则返回0
mp.swap(mp1); 交换2个容器
*/
测试:
void test02()
{
map mp1; // 1
mp1.insert(pair(1, 11)); mp1.insert(pair(2, 22));
mp1.insert(pair(4, 44)); mp1.insert(pair(3, 33));
cout << mp1.size() << endl;
cout << mp1.empty() << endl;
map mp2; // 1
mp2.insert(pair(1, 66)); mp2.insert(pair(4, 99));
mp2.insert(pair(2, 77)); mp2.insert(pair(3, 88));
cout << "交换前" << endl;
printm(mp1); printm(mp2);
mp2.swap(mp1);
cout << "交换后" << endl;
printm(mp1); printm(mp2);
}
/*插入和删除
mp.insert(); 1插入元素
mp.clear(); 2清空容器
mp.erase(pos); 3删除迭代器pos处的元素
mp.erase(begin,end);4删除迭代器区间begin,end之间的元素
mp.erase(val); 5删除容器中key值为val的元素
*/
测试:
void test03()
{
// insert又有4种方式:
map m;
m.insert(pair(1, 10));// 1.1
m.insert(make_pair(2, 20)); // 1.2
m.insert(map::value_type(3, 30));// 1.3
m[4] = 40; // 1.4
printm(m);
m.erase(m.begin()); // 3
printm(m);
m.erase(3); // 5
printm(m);
//m.erase(m.begin(), m.end()); // 4 相当于清空
m.clear(); // 2
printm(m);
}
ps:insert又有 4种方式,其中使用[]访问元素的方法不建议拿来插入元素,因为当我们访问到不存在的key时,它会自动生成一个val为0的元素
因此,一般情况下,[]只用来访问确定已经存在的key值的元素
/* 查找与统计
mp.find(key); 查找key元素是否存在,存在返回其位置的迭代器,否则返回mp.end();
mp.count(key); 统计元素key的个数
*/
由于map容器中没有重复元素,因此count只有0/1
测试:
void test04()
{
map mp1;
mp1.insert(pair(1, 11)); mp1.insert(pair(2, 22));
mp1.insert(pair(4, 44)); mp1.insert(pair(3, 33));
map::iterator pos = mp1.find(3);
if (pos != mp1.end())
cout << "有了:" << (*pos).first << pos->second << endl;
else
cout << "没有" << endl;
cout << mp1.count(3) << endl;
}
注意:应在插入数据前就指定其排序规则,否则都插入了无法排序
①内置数据类型排序
void test05()
{
map m1;
m1.insert(pair(1, 11)); m1.insert(pair(2, 22));
m1.insert(pair(4, 44)); m1.insert(pair(3, 33));
printm(m1);
// 进行降序排列
map m2;
m2.insert(pair(1, 11)); m2.insert(pair(2, 22));
m2.insert(pair(4, 44)); m2.insert(pair(3, 33));
for (map::iterator it = m2.begin(); it != m2.end(); it++)
{
cout << it->second << " ";
}
cout << endl;
}
加上仿函数:
class MYcompare
{
public:
bool operator()(int x, int y)const
{
return x > y;
}
};
描述:现招聘10个新员工(ABCDEFGHIJ),进入公司后,需要指派员工到哪个部门工作。
员工信息:姓名+工资。部门:策划+美术+研发
随机给10名员工分配部门与工资
使用multimap进行信息的插入:使用对组(key - 部门编号,val - 员工)
分部门展示员工信息
①创建10名员工,存放至vector容器中
// 创建员工
vector v;
createworker(v);
员工信息Worker
class Worker
{
public:
string m_name;
int m_salary;
};
创建员工createWorker()
void createworker(vector& v)
{
string nameSeed = "ABCDEFGHIJ";
for (int i = 0; i < 10; i++)
{
Worker worker; // 创建一名员工
worker.m_name = "员工";
worker.m_name += nameSeed[i];// 创建员工名字+随机数
worker.m_salary = 10000 + rand() % 10000;//创建员工工资,10000-19999
v.push_back(worker);//将员工插入到vector容器中
}
}
②对员工进行随机分组
// 员工分组
multimap m;
setDept(v,m);
随机分配部门setDept()
void setDept(vector &v, multimap&m)
{
// 遍历v的每个元素找到每个员工
for (vector::iterator it = v.begin(); it != v.end(); it++)
{
int DeptID = rand() % 3; // 随机分配部门0、1、2
m.insert(make_pair(DeptID, *it));
}
}
③查看员工
// 查看员工
showWorker(m);
查看员工showWorker()
有2种方法,1种是直接遍历mutilmap容器,如果key值符合部门对应的012,则输出对应val的员工信息
2种是使用multimap的find与count函数来找到对应部门的员工
void showWorker(multimap m)
{
cout << "策划部门有:" << endl;
for (multimap::iterator it = m.begin(); it != m.end(); it++)
{
if (it->first == 0)
{
cout << "员工名为:" << it->second.m_name <<
"工资为:" << it->second.m_salary << endl;
}
}
cout << "美术部门有:" << endl;
for (multimap::iterator it = m.begin(); it != m.end(); it++)
{
if (it->first == 1)
{
cout << "员工名为:" << it->second.m_name <<
"工资为:" << it->second.m_salary << endl;
}
}
cout << "研发部门有:" << endl;
for (multimap::iterator it = m.begin(); it != m.end(); it++)
{
if (it->first == 2)
{
cout << "员工名为:" << it->second.m_name <<
"工资为:" << it->second.m_salary << endl;
}
}
//----------------------------------------------------------------------------
cout << "策划部门有:" << endl;
multimap::iterator pos = m.find(CEHUA);
int count = m.count(CEHUA);
int index = 0;
for (pos; pos != m.end() && index < count; pos++, index++)
{
cout << "员工名为:" << pos->second.m_name <<
"工资为:" << pos->second.m_salary << endl;
}
cout << "美术部门有:" << endl;
pos = m.find(MEISHU);
count = m.count(MEISHU);
index = 0;
for (pos; pos != m.end() && index < count; pos++, index++)
{
cout << "员工名为:" << pos->second.m_name <<
"工资为:" << pos->second.m_salary << endl;
}
cout << "研发部门有:" << endl;
pos = m.find(YANFA);
count = m.count(YANFA);
index = 0;
for (pos; pos != m.end() && index < count; pos++, index++)
{
cout << "员工名为:" << pos->second.m_name <<
"工资为:" << pos->second.m_salary << endl;
}
}
最后加上随机数种子
srand((unsigned int)time(NULL));