QHash
不同之处在于:
(1)QHash提供比QMap更快的查找,但所需空间更大。
(2)QMap默认按照键值升序排序;。使用QHash按照键值任意排序。
(3)QMap的键类型必须提供operator <()。QHash的键类型必须提供operator ==()和称为qHash()的全局哈希函数。
如果使用QHash中已存在的键调用insert(),则先前的值将被删除,如:
hash.insert("plenty", 100);
hash.insert("plenty", 2000);
// hash.value("plenty") == 2000
QHash hash;
...
foreach (int value, hash)
cout << value << Qt::endl;
Qt进入foreach循环时会自动获取容器的副本,如果在迭代时修改容器,则不会影响循环(如果不修改容器,则仍会进行复制,但是由于隐式共享,复制容器非常快)。由于foreach会创建容器的副本,因此对变量使用非常量引用将不允许您修改原始容器,它只会影响副本。
Qt foreach循环的替代方法for是C ++ 11和更高版本中的基于范围的。但是,基于范围的for可能会强制Qt容器分离,而foreach不会。使用foreachAlways复制容器,对于STL容器通常并不容易。建议使用foreach Qt容器,并使用基于范围的forSTL 容器。
QHash的键类型除了是可分配的数据类型外,还具有其他要求:它必须提供operator ==(),并且该类型的名称空间中还必须有一个qHash()函数,该函数返回键类型的参数的哈希值。该qHash()函数计算基于密钥的数值。只要给定相同的参数,它总是返回相同的值,它就可以使用任何可以想象的算法。换句话说,如果e1 == e2,则qHash(e1) == qHash(e2)也必须成立。但是,为了获得良好的性能,qHash()函数应尝试最大程度地为不同的键返回不同的哈希值。例如:
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
class Employee
{
public:
Employee() {}
Employee(const QString &name, QDate dateOfBirth);
...
private:
QString myName;
QDate myDateOfBirth;
};
inline bool operator==(const Employee &e1, const Employee &e2)
{
return e1.name() == e2.name()
&& e1.dateOfBirth() == e2.dateOfBirth();
}
inline uint qHash(const Employee &key, uint seed)
{
return qHash(key.name(), seed) ^ key.dateOfBirth().day();
}
#endif // EMPLOYEE_H
注意:如果是自定义类型或是第三方库类型作为哈希表的键值时,对perator ==()和qHash()函数的定义必须是全局的,要定义在使用QHash
error C2665: “qHash”: 25 个重载中没有一个可以转换所有参数类型
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHashBits(const void *p, size_t size, uint seed = 0) Q_DECL_NOTHROW;
Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(char key, uint seed = 0) Q_DECL_NOTHROW { return uint(key) ^ seed; }
Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(uchar key, uint seed = 0) Q_DECL_NOTHROW { return uint(key) ^ seed; }
Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(signed char key, uint seed = 0) Q_DECL_NOTHROW { return uint(key) ^ seed; }
Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(ushort key, uint seed = 0) Q_DECL_NOTHROW { return uint(key) ^ seed; }
Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(short key, uint seed = 0) Q_DECL_NOTHROW { return uint(key) ^ seed; }
Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(uint key, uint seed = 0) Q_DECL_NOTHROW { return key ^ seed; }
Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(int key, uint seed = 0) Q_DECL_NOTHROW { return uint(key) ^ seed; }
Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(ulong key, uint seed = 0) Q_DECL_NOTHROW{return (sizeof(ulong) > sizeof(uint))? (uint(((key >> (8 * sizeof(uint) - 1)) ^ key) & (~0U)) ^ seed) : (uint(key & (~0U)) ^ seed);}
Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(long key, uint seed = 0) Q_DECL_NOTHROW { return qHash(ulong(key), seed); }
Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(quint64 key, uint seed = 0) Q_DECL_NOTHROW{ return uint(((key >> (8 * sizeof(uint) - 1)) ^ key) & (~0U)) ^ seed;}
Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(qint64 key, uint seed = 0) Q_DECL_NOTHROW { return qHash(quint64(key), seed); }
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION uint qHash(float key, uint seed = 0) Q_DECL_NOTHROW;
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION uint qHash(double key, uint seed = 0) Q_DECL_NOTHROW;
#ifndef Q_OS_DARWIN
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION uint qHash(long double key, uint seed = 0) Q_DECL_NOTHROW;
#endif
Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(const QChar key, uint seed = 0) Q_DECL_NOTHROW { return qHash(key.unicode(), seed); }
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QByteArray &key, uint seed = 0) Q_DECL_NOTHROW;
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QString &key, uint seed = 0) Q_DECL_NOTHROW;
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QStringRef &key, uint seed = 0) Q_DECL_NOTHROW;
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QBitArray &key, uint seed = 0) Q_DECL_NOTHROW;
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(QLatin1String key, uint seed = 0) Q_DECL_NOTHROW;
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qt_hash(const QString &key) Q_DECL_NOTHROW;
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qt_hash(const QStringRef &key) Q_DECL_NOTHROW;
template inline uint qHash(const T *key, uint seed = 0) Q_DECL_NOTHROW
{
return qHash(reinterpret_cast(key), seed);
}
template inline uint qHash(const T &t, uint seed)
Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(t)))
{ return (qHash(t) ^ seed); }
template inline uint qHash(const QPair &key, uint seed = 0)
Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(key.first, seed)) && noexcept(qHash(key.second, seed)))
{
uint h1 = qHash(key.first, seed);
uint h2 = qHash(key.second, seed);
return ((h1 << 16) | (h1 >> 16)) ^ h2 ^ seed;
}
qHash中关于处理指针键值的哈希函数,如下:
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHashBits(const void *p, size_t size, uint seed = 0) Q_DECL_NOTHROW;
template
{
return qHash(reinterpret_cast
}
指针哈希函数应用如下:(其中handle为第三方库智能指针,1、3例指针转int可能会溢出)
inline uint qHash(const Handle(AIS_Shape)& key)
{
return qHash(reinterpret_cast(key.get()));
//return qHashBits(key.get(), sizeof(AIS_Shape*), 0);
//return qHash((int)key.get());
}
|
关键字查找 |
插入 |
||
平均 |
最差 |
平均 |
最差 |
|
QMap |
O(log n) |
O(log n) |
O(log n) |
O(log n) |
QMultiMap |
O(log n) |
O(log n) |
O(log n) |
O(log n) |
QHash |
Amort. O(1) |
O(n) |
Amort. O(1) |
O(n) |
QSet |
Amort. O(1) |
O(n) |
Amort. O(1) |
O(n) |
使用QVector,QHash和QSet,附加项的性能摊销为O(log n)。在插入项目之前,可以通过调用QVector :: reserve(),QHash :: reserve()(或QSet :: reserve()并使用预期的项目数将其降至O(1)。