目录
0list
双向链表,数据由两个部分组成,一个数据域一个指针域。
优缺点:
- 采用动态存储分配,不会造成内存浪费和溢出
- 链表执行插入和删除操作十分方便,修改指针即可
- 链表灵活,但是空间和时间额外耗费较大
迭代器:bidirectional Iterators
List有一个重要性质,插入操作和删除操作都不会造成原有的迭代器的list迭代器的失效。
这在vector是不成立的,因为vector的插入操作可能造成记忆体重新配置,导致原有的迭代器全部失效,甚至list元素的删除,也只
有被删除元素的迭代器失效,其他迭代器不受任何影响。
头指针
#include<list>
using namespace std;
1list的API
list<DataType>listT;//list采用模板类实现,对象的默认构造函数
list(beg,end);//构造函数将(beg,end)区间中的元素拷贝给本身
list(n,len);//构造函数将n个elen拷贝给本身
list(const list & Lst);//拷贝构造函数
push_back(elen);//在容器尾部加入一个元素
pop_back();//删除容器中最后一个元素
push_front(elen);//在容器开头插入一个元素
pop_front();//从容器开头移除第一个元素
insert(pos,elen);//在pos位置插入elen元素的拷贝,返回新数据的位置
insert(pos,n,elen);//在pos位置插入n个elen数据,无返回值
insert(pos,beg,end);//在pos位置插入【beg,end】,无返回值
clear();//清空
erase(beg,end);//删除【beg,end】区间的数据,返回下一个数据的位置
erase(pos);//删除pos位置的数据,返回下一个数据的位置
remove(elen);//删除容器中所有与elen值匹配的元素
list<int>L(10,10);
list<int>L2(L.begin(),L.end());
PrintList(L);
PrintList(L2);
list<int>L3;
L3.push_back(10);
L3.push_back(30);
L3.push_back(50);
L3.push_front(100);
L3.push_front(300);
L3.push_front(500);
PrintList(L3);
Reverse_PrintList(L3);
//删除两端数据
L3.pop_front();
L3.pop_back();
PrintList(L3);
L3.insert(L3.begin(),1000);//在开始位置插入1000
PrintList(L3);
L3.remove(300);
PrintList(L3);
其中,打印和逆序打印,接口如下:
void PrintList(list<int> L)
{
qDebug()<<"进入遍历:";
for(list<int>::iterator it = L.begin();it != L.end();it++)
{
qDebug()<<*it;
}
}
void Reverse_PrintList(list<int> L)
{
qDebug()<<"进入逆序遍历:";
for(list<int>::reverse_iterator it = L.rbegin();it != L.rend();it++)
{
qDebug()<<*it;
}
}
程序输出:
size();//返回容器中的元素个数
empty();//判断容器是否为空
resize(num);//重新指定容器长度为num
resize(num,elen);//重新制定list长度为num,如果变长,多余部分用elen补充
assign(beg,end);//将【beg,end】区间中的数据拷贝给本身
assign(n,elen);//将n个elen拷贝给赋值本身
list & operator=(const list & lst);//重载等号运算符
swap(lst);//将list和本身元素交换
front();//返回第一个元素
back();//返回最后一个元素
具体操作:
qDebug()<<"L3大小:"<<L3.size();
L3.resize(10,0);
PrintList(L3);
list<int>L4;
L4.assign(L3.begin(),L3.end());
PrintList(L4);
reverse();//反转链表
sort();//排序
list<int>L5;
L5.push_back(1);
L5.push_back(3);
L5.push_back(5);
L5.push_back(7);
L5.push_back(9);
PrintList(L5);
L5.reverse();
PrintList(L5);
list<int>L6;
L6.push_back(1);
L6.push_back(3);
L6.push_back(2);
L6.push_back(5);
L6.push_back(7);
PrintList(L6);
L6.sort();
PrintList(L6);
2set/multiset
set/multiset的特性是所有元素会根据元素的值自动进行排序
set/multiset以红黑树为底层机制,其查找效率非常好,set容器中不允许重复的元素,multiset则允许重复元素存在
set<T> st;// 默认构造函数
multiset<T> mst;// multiset默认构造函数
set(const set &st);// 拷贝构造函数
set &operator=(const set &st); // 重载等号运算符
swap(st);// 交换两个集合容器中的元素
size();// 返回容器中元素的数目
empty();// 判断容器是否为空
insert(elem);// 在容器中插入元素
clear();// 清空所有元素
erase(pos);// 删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg, end);// 删除区间[beg, end)的所有元素
erase(elem);// 删除容器中值为elem的元素
set<int> T;
T.insert(5);
T.insert(3);
T.insert(4);
T.insert(2);
T.insert(9);
Print_set(T);
if(T.empty())
{
qDebug()<<"空";
}
else
{
qDebug()<<"大小:"<<T.size();
}
qDebug()<<"移除首位元素";
T.erase(T.begin());
Print_set(T);
qDebug()<<"移除第3个元素";
T.erase(3);
Print_set(T);
find(key);// 查找键key是否存在,若存在,返回该元素的迭代器;若不存在,则返回map.end()
lower_bound(keyElem);// 返回第一个key>=keyElem元素的迭代器,若不存在,则返回map.end()
upper_bound(keyElem);// 返回第一个key>keyElem元素的迭代器,若不存在,则返回map.end()
equal_range(keyElem);// 返回容器中key和keyElem相等的上下限的两个迭代器,若不存在,则返回map.end(),此上下限就是lower_bound和upper_bound
set<int>::iterator pos = T.find(3);
if(pos!=T.end())
{
qDebug()<<"没有找到";
}
else
{
qDebug()<<"找到:值为"<<*pos;
}
pair<set<int>::iterator,set<int>::iterator> ret = T.equal_range(4);
if(ret.first==T.end())
{
qDebug()<<"没有找到";
}
else
{
qDebug()<<"找到:值为"<<*(ret.first);
}
if(ret.second==T.end())
{
qDebug()<<"没有找到";
}
else
{
qDebug()<<"找到:值为"<<*(ret.second);
}
注意:equal_range的接口,返回两个值,一个是lower_bound(keyElem),一个是upper_bound(keyElem)
此时使用pair进行接受返回值:
关于对组(pair)
pair<string,int>p(string("Tom"),100);
cout<<"name:"<<p.first<<endl;
cout<<"age:"<<p.second<<endl;
pair<string,int>p2 = make_pair("jerry",10);
cout<<"name:"<<p2.first<<endl;
cout<<"age:"<<p2.second<<endl;
访问元素方式:第一个:frist;第二个:second;创建方式也同上
上述程序输出:
set不允许插入相同的值
关于set,不允许插入重复的内容, 如果擦入会怎样?
set<int> T;
T.insert(9);
T.insert(9);
Print_set(T);
程序没有报错,打印之后输出了一个数值。
set<int> T;
pair<set<int>::iterator,bool> it1 = T.insert(9);
if(it1.second == false)
{
qDebug()<<"插入失败";
}
else
{
qDebug()<<"插入成功";
}
pair<set<int>::iterator,bool> it2 = T.insert(9);
if(it2.second == false)
{
qDebug()<<"插入失败";
}
else
{
qDebug()<<"插入成功";
}
Print_set(T);
查阅insert返回值可以看到,insert返回的是一个对组,对组第一个变量是迭代器,返回的是插入位置,第二个是bool变量,返回的是是否插入成功。
从输出也可以看出来,只要一次插入成功了。
从大到小排序
set因为使用的是红黑树的结构,以此来在插入的时候就完成排序,此时要进行从大到小的排序
方法:在插入之前就规定好排序规则,使用仿函数
在插入前就要规定好原则,那么只能在set创建的时候了,set创建的过程中有一个重载,允许用户输入仿函数修改排序规则
仿函数部分:
class MyCompare
{
public:
bool operator()(int v1,int v2)
{
return v1>v2;
}
};
使用方法:
set<int,MyCompare> T;
T.insert(5);
T.insert(3);
T.insert(4);
T.insert(2);
pair<set<int>::iterator,bool> it1 = T.insert(9);
Print_set(T);
其中的输出API(要和set的建立一一对应)
void Print_set(set<int,MyCompare> T)
{
qDebug()<<"遍历:";
for(set<int,MyCompare>::iterator it = T.begin();it!=T.end();it++)
{
qDebug()<<*it;
}
}
输出:
插入自定义类型
其他的数据类型也可以如此
自定义类型:
class MyCompare
{
public:
bool operator()(const PersonSet & p1,const PersonSet & p2)
{
if(p1.age>p2.age)
return true;
else
return false;
}
};
仿函数:
class MyCompare
{
public:
bool operator()(const PersonSet & p1,const PersonSet & p2)
{
if(p1.age>p2.age)
return true;
else
return false;
}
};
打印接口:
void Print_set(set<PersonSet,MyCompare> T)
{
// qDebug()<<"遍历:";
for(set<PersonSet,MyCompare>::iterator it = T.begin();it!=T.end();it++)
{
cout<<"age:"<<(*it).age<<"name:"<<(*it).name<<endl;
}
}
具体操作:
set<PersonSet,MyCompare> T;
PersonSet p1 = {string("1"),1};
PersonSet p2 = {string("2"),2};
PersonSet p3 = {string("3"),3};
PersonSet p4 = {string("100"),100};
PersonSet p5 = {string("123"),123};
T.insert(p1);
T.insert(p2);
T.insert(p3);
T.insert(p4);
T.insert(p5);
Print_set(T);
输出:
唯一要注意的是,打印接口,(*it)先访问存在迭代器中的值,也就是PersonSet类型的值,之后再进行访问其他成员的操作