关联式容器

关联式容器

关联式容器持有同一类型的条目,每个条目被一个键所索引。 Qt提供两种主要的关联式容器: QMap<K, T>QHash<K, T>

QMap<K, T>是一种按照键值从小到大的顺序存储键值对的结构。 这个装置提供了一个好的性能,对于检索,插入和中序遍历(in-order iteration)。 在内部,QMap<K, T>用跳跃表(skip-list)来实现。

图 11.6. A map of QString to int

amap[1]

向map中插入条目的一个简单方法是调用insert()

QMap<QString, int> map;
map.insert("eins", 1);
map.insert("sieben", 7);
map.insert("dreiundzwanzig", 23);

或者,我们可以简单地像下面那样为一个给定的键赋值:

map["eins"] = 1;
map["sieben"] = 7;
map["dreiundzwanzig"] = 23;

[]操作符可以用来进行插入和解引用。 在一个non-const map中,如果[]为一个不存在的键解引用,那么系统将会用给定的键和一个空值来新建一个条目。 为了避免意外创建空值,我们可以用value()函数代替[]来引用条目。

int val = map.value("dreiundzwanzig");

如果键不存在,将会用值类型的缺省构造函数返回一个缺省值,并且没有新的条目被创建。 对于基本类型和指针类型,返回0。 我们可以另指定缺省值作为value()的第二个参数,例如:

int seconds = map.value("delay", 30);

这相当于:

int seconds = 30;
if (map.contains("delay"))
    seconds = map.value("delay");

QMap<K, T>中的KT可以是基本类型像intdouble,指针类型,或拥有缺省构造函数,拷贝构造函数,和赋值操作符的类。 另外,K类型必须提供operator<(),因为QMap<K, T>使用这个操作符按键值升序来存储条目。

QMap<K, T>有一对便捷函数,keys()values(),它们特别有用当处理小数据集时。 它们返回map的键和值的QList

Maps通常是single-valued: 如果为存在的键赋新值,那么旧值就会被新值替换掉,确保没有两个条目共享同一个键。 多个键值对拥有相同的键也是可能的,通过使用insertMulti()函数或者是便捷子类QMultiMap<K, T>QMap<K, T>的重载函数values(const K &)返回一个QList,它包含指定键对应的所有的值。 例如:

QMultiMap<int, QString> multiMap;
multiMap.insert(1, "one");
multiMap.insert(1, "eins");
multiMap.insert(1, "uno");
QList<QString> vals = multiMap.values(1);

QHash<K, T>是将键值对存储在哈希表中的结构。 它的接口和QMap<K, T>几乎相同,但是它对K模板参数要求不同而且它的检索速度要比QMap<K, T>更快。 另外不同的是,QHash<K, T>是无序的。

除了容器中值类型的一些标准要求外,QHash<K, T>中的K类型还被要求提供operator==()并且它被全局函数qHash()所支持,此函数返回一个键的哈希值。 Qt已经为整型,指针类型,QCharQString,和QByteArray提供qHash()函数。

QHash<K, T>为内部hash表自动分配bucket中的一个素数,并重新调整大小当插入或删除条目。 调用reserve()来指定预期的条目数或者根据当前条目数调用squeeze()来收缩hash表可以提升性能。 一般的习惯是用期望的最大条目数调用reserve(),然后插入数据,最后调用squeeze()减少内存占用如果条目数比期望的要少。

Hashes通常是single-valued,但是同样的键可以有多个值,通过使用insertMulti()函数或QMultiHash<K, T>便捷子类。

除了QHash<K, T>,Qt还提供一个QCache<K, T>类,它能用来缓存伴有键的对象,而且Qt还提供一个QSet<K>容器,只用来存储键。 在内部,这两个类都依赖QHash<K, T>并且它们对K类型的要求和QHash<K, T>一样。

遍历关联式容器的最简单的方法是使用Java风格的迭代器。 因为迭代器必须既要接触键又要接触值,Java风格关联式容器迭代器与序列式容器的工作稍微有些不同。 主要的不同是next()previous()函数返回一个代表键值对的对象,而不是简单的一个值。 通过对象的key()value()来存取键和值。 例如:

QMap<QString, int> map;
...
int sum = 0;
QMapIterator<QString, int> i(map);
while (i.hasNext())
    sum += i.next().value();

如果我们需要同时存取键和值,我们可以简单地忽略next()previous()的返回值并用迭代器的key()previous()函数,操作在最后一个被跳过的条目上。

QMapIterator<QString, int> i(map);
while (i.hasNext()) {
    i.next();
    if (i.value() > largestValue) {
        largestKey = i.key();
        largestValue = i.value();
    }
}

可变迭代器有一个setValue()函数用来修改当前条目的值:

QMutableMapIterator<QString, int> i(map);
while (i.hasNext()) {
    i.next();
    if (i.value() < 0.0)
        i.setValue(-i.value());
}

STL风格的迭代器也提供key()value()函数。 使用nonconst迭代器类型,value()返回一个non-const引用,允许我们在迭代的时候修改值。 注意尽管这些迭代器被成为“STL风格”,但它们与STL的map<K, T>迭代器有明显的不同,STL的是基于pair<K, T>的。

foreach循环也能用于关联式容器,但只工作在键值对的值上。 如果我们同时需要条目的键和值,我们可以在嵌套的foreach循环中调用keys()values(const K &),像下面那样:

QMultiMap<QString, int> map;
...
foreach (QString key, map.keys()) {
    foreach (int value, map.values(key)) {
        do_something(key, value);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值