QT开发STL

容器类

Qt的容器类比STL(标准模板库)种的容器类更轻巧、安全和易于使用。

1
2
3
4
5
QList<QString> aList;
aList.append("Monday");
aList.append("uesday");
aList.append("Wednesday");
QString str=aList[0];qDebug()<<str; //显示"Monday'

顺序容器通过元素在容器中的位置顺序存储和访问,没有key值概念的
关联容器通过键(key)存储和读取元素(有key值和value是同一个值,set的时候,只能看到一个值,这种就不存在关联;其他都有key值,找到value值)

Qt的容器类分为顺序容器和关联容器

顺序容器:QList(指针),QLinkedList(链表),QVector(对象),QStack(栈)和QQueue(队列)
关联容器QMap(key值不能重复,存储连续),QMultiMap(key值可以重复),QHash(通过hash值算出位置存储),QMultiHash(key值可以重复,)和QSet(key与value值相同,key就是value)

QLis:数组列表

1
2
3
4
QList<QString> list;
list<<"one"<<"two"<<"three";
QString str1=list[1]; //str1 == "two"
QString str0=list.at(0); //str0 == "one"

QLinkedList: 除了不提供下标索引的数据访问,和QList其他函数接口基本相同
QVector : 函数接口与QList几乎完全相同,访问性能更高,因为是连续存储.但是插入和删除不方便

QStack:LIFO

1
2
3
4
5
6
QStack<int> stack;
stack.push(10);
stack.push(20);
stack.push(30);
while(!stack.isEmpty())
qDebug()<<stack.pop();

Queue:FIFO 先进先出

1
2
3
4
5
6
QQueue<int> queue;
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
while(!queue.isEmpty())
qDebug()<<queue.dequeue();

QSet:

基于散列表,存放位置未知的,存放位置是否为cat,不是,往下存,是的就不再存储了

1
2
3
4
QSet<QString> set;
set<<"dog"<<"cat"<<"tiger"
if(set.contains("cat"))
qDebug()<<"the set has a cat";

QMap:

按键值的顺序存储(如果插入重复的值,就忽略,键值是唯一的)

1
2
3
4
5
6
7
8
9
10
11
QMap<QString,int> map;
map["one"]=1; //如果不存在就会创建
map["two"]=2;
map["three"]=3;
map.insert("four",4);
map.remove("two"); //删除"two"
int num1=map["one"];
int num2=map.value["two"]; //没有"two",就给默认值 0
int num3=map["five"]; //没有"five",就给默认值 0
int timeout=map.value("TIMEOUT"30);//没有TIMEOUT直接给个30
qDebug()<<num1<<num2<<num3<<timeout;//1 0 0 30
运行结果
key: one two three four
value: 1 2->0 3 4

QMultiMap:

QMap的子类,键值可以重复

1
2
3
4
5
6
7
8
9
QMultiMap<QStringint> map1,map2,map3;
map1.insert("plenty",100);
map1.insert("plenty",2000);
map2.insert("plenty",5000);
map3=map1+map2; //键值可以重复,所以这里map1和map2加在一起给map3
qDebug()<<map3.size();//3
QList<int> values=map3.values("plenty");//将plenty的值存储到values数组表中
foreach(int i,values) //values 一个一个放入i中,然后打印出来
qDebug()<<i; //5000 2000 100

QHash必须提供”==”于QMap用法类似,QMultiHash与QMultiMap用法类似

容器类的迭代3.4

迭代器就是为访问容器里面的数据,提供的一种方法;提供了一种方法对容器进行迭代访问,无需暴露容器的内部结构。迭代器被设计为用于遍历容器内的元素,如数组、列表、映射等。

QT有两种迭代器:java类型的迭代器(易于使用)和STL类型的迭代器(效率高)
Java类型迭代器

容器类 只读迭代器 读写迭代器
QList<T>QQueue<T> QListlterator<T> QMutableListlterator<T>
QLinkedList<T> QLinkedListlterator<T> QMutableLinkedListlterator<T>
QVector<T>QStack<T> QVectorlterator<T> QMutableVectorlterator<T>
Qset<T> QSetiterator<T> QMutableSetiterator<T>
QMap<Key,T>QMultiMap<Key,T> QMaplterator<Key,T> QMutableMaplterator<Key,T>
Qhash<Key,T>QMultiHash<Key,T> QHashlterator<Key,T> QMutableHashlterator<Key,T>
1
2
3
4
5
6
7
QList<QString> list;
......
QListIterator<QString> i(list);
while(i.hasNext()) //判断在迭代器指针后面是否还有数据项 必须配合使用
{
qDebug()<<i.next(); //跳过一个数据项,并返回其值
}

反向遍历

1
2
3
4
5
QListIterator<QString> i(list);
while(i.hasPrevious()) //判断前面是否有元素
{
qDebug<< i.previous();//跳过当前元素,并返回值
}
常用函数 功能
void toFront() 迭代器移动到列表的最前面(第一个数据项之前)
void toBack() 迭代器移动到列表的最后面(最后一个数据项之后)
bool hasNext() 如果迭代器不是位于列表最后位置,返回true
const T& next() 返回下一个数据项,并且迭代器后移一个位置
const T&peekNext() 返回下一个数据项,但是不移动迭代器位置
bool hasPrevious() 如果迭代器不是位于列表最前面,返回true
const T& previous() 返回前一个数据项,并且迭代器前移一个位置
const T& peekPrevious() 返回前一个数据项,但是不移动迭代器指针

//删除奇数项

1
2
3
4
5
6
7
8
9
10
11
QList<int> list;
list<<1<<2<<3<<4<<5;
QMutableListIterator<int> i(list);

whie(i.hasNext())
{
if(i.next() % 2 != 0)
{
i.remove();//remove()函数移除next()函数刚刚跳过的一个数据项,不会是迭代器失效。setValue()函数可以修改刚刚跳过去的数据项的值
}
}

容器内数据: 2 4;

关联容器类的迭代器的使用

关联容器上面表中函数都可以使用

具有上表所示的所有函数,主要是增加了key()和value()函数用于获取刚刚跳过的数据项的键和值

1
2
3
4
5
6
7
8
9
10
11
12
QMap<QString,QString> map;
map.insert("Paris","France");
map.insert("New York","USA");
map.insert("Mexico City","USA");
map.insert("Moscow","Russia");

QMutableMaplterator<QString,QString>i(map); //容器初始化迭代器
while(i.hasNext())
{
if(i.next().key().endsWith("City"))
i.remove();
}

删除Value是”USA”的项

1
2
while(i.findNext("USA"))
i.remove();

STL类型迭代器

与C++标准类型的迭代器是一样的

容器类 只读迭代器 读写迭代器
QList、QQueue QList::const_iterator QList::iterator
QLinkedList QLinkedList::const_iterator QLinkedList::iterator
QVector、QStack QVector::const_iterator QVector::iterator
QSet QSet::const_iterator QSet::iterator
QMap<key,T>
QMultiMap<key,T>
QMap<key,T>::const_iterator QMap<key,T>::iterator

可以使用const_reverse_iteratorreverse_iterator 定义相应的反向迭代器

reverse:反转、交换、颠倒

STL类型的迭代器是数组的指针,所以”++”运算符使迭代器指向下一个数据项,运算符返回数据项内容

STL迭代器直接指向数据项,尾后的值,不要取值。

begin:开始 、insert:插入 multi:多种,多数

顺序容器类的迭代器的用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
QList<QString> list;
list<<"A"<<"B"<<"C"<<"D";
QList<QString>::const_iterator i;//创建迭代器
for(i = list.constBegin();i!=list.constEnd();i++)
{
qDebug()<<*i;
}

QList<QString>::reverse_iterator j;
for(j = list.rbegin(); j!=list,rend();j++)
{
*j->toLwer();
qDebug<<*j;
}

关联容器类的迭代器用法

1
2
3
4
5
6
7
8
QMap<int,int> map;
map.insert(1,11);
map.insert(2,22);
QMap<int,int>::const_iterator i;
for(i = map.constBegin(); i!=map.constEnd();i++)
{
qDebug()<<i.key()<<':'<<i.value();
}
1
2
3
4
5
6
7
8
9
10
11
QMultiMap<int,int> map; //同一个键值,就会有链表
map.insert(1,11);
map.insert(2,22);
map.insert(2,222);
//这里只调用了一次,下面遍历的时候拿到的值是一样的
const QList sizes = map.values(2);// qt使用了隐式共享 只有sizes发生了数据修改时,才会将共享对象的数据复制给sizes,sizes直接指向key = 2的值链表
QList<int>::const_iterator i;
for(i = sizes.begin();i!=sizes.end;i++)
{
qDebug()<<*i; //结果 222 22
}

下面的代码是错误的

1
2
for(i = map.values(2).begin();i!=map.values(2).end();i++)//可能这个begin遇不到end
qDebug()<<*i;

map.values(2).begin()map.values(2).end() 拿到的数值可能不一样(发生了复制行为),也可能一样,不一样就产生错误了 std::addressof(*)解引用

注意:

对于STL类型的迭代器,隐式共享还涉及另外一个问题,既当有一个迭代器在操作一个容器变量时,不要去复制这个容器变量(会有不安全状态)

foreach关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
QLinkedList<QString> list;
list.append("a");
list.append("b");
foreach(auto str,list)
qDebug()<<str;

QMultiMap<QString,int> map;
map.insert("A",1);
map,insert("A",2);
map.insert("B",2);
foreach(auto str,map.uniqueKeys()) //uniqueKeys 唯一的 唯一密钥
{
foreach(auto num , map.values(str))
qDebug()<<str<<":"<<num;
}

结果: a b

“A”:2

“A”:1

“B”:2