关于C#:QMap或QHash中的QSet

QSet in QMap or QHash

我有QMap,并且我想将其作为键,但不能这样做,因为QSet不具有可比性。
例如:

1
2
3
4
5
6
7
8
QSet<int> intSet;
QMap<QSet<int>, char> charSet;

intSet.insert(1);
intSet.insert(2);
intSet.insert(3);

charSet.insert(intSet, '6');

有什么办法可以使它工作?如果我从QSet继承并定义operator <,应该如何实现?即:比较的逻辑应该是什么?

注意:我太在乎性能了


您似乎知道如何使它起作用:定义一个operator<(const QSet<int>&)函数(我不认为Qt要求您将QSet子类化才能起作用,我知道STL不需要)。

显然,在无序集合上实现比较器将很困难。我认为,要使其以恒定的时间运行是不可能的。您可以尝试先检查大小,然后再将两个内容排序并比较为列表。

但大致上:不要这样做。这是一种虐待。当然,您可以将集合键的某些内容用于可变数据结构。集合中的整数空间是否固定且较小(即始终在0-1024或其他范围内)?然后尝试存储在QByteArray中的位掩码。等等...


您可以创建这样的哈希方法

1
2
3
4
5
6
7
8
uint qHash(const QSet<int>& set) {
  uint seed = 0;

  for(int x : set) {
     seed ^= qHash(x) + 0x9e1559a9 + (seed << 6) + (seed >> 2);
  }
  return seed;
}

然后您的QMap将像这样

1
QMap<uint, char> charSet;

其中uint是先前方法的结果。

实际上这种方式并不是100%稳定的,这取决于您的哈希函数。


似乎您不需要值语义。为何不使用:

1
2
3
QHash<QSet<int> *, char> charSet;
//then to insert a set
charSet.insert(& intSet, '6');

但是对于每个集合,只有一个字符与一个集合相对应,那么为什么不扩展QSet并添加其他成员呢?


假设您不担心性能(如果您使用容器作为键,我认为这是一个合理的假设),那么我会做这样的事情。

1
2
3
4
5
6
7
8
9
10
QSet<int> intSet;
intSet << 1 << 2 << 3 << 3 << 4;

QVector<int> intVector;
intVector.reserve(intSet.size());
qCopy(intSet.begin(), intSet.end(), std::back_inserter(intVector)); // QVector doesn't have a std::vector range constructor atm
qSort(intVector);

QHash<QVector<int>, char> charHash;
charHash[intVector] = '6';

添加起来会很慢,但是查找应该(相对)快。

我建议您拿出一个更好的钥匙。也许是一个具有固定数量的int的简单类,您只需定义必要的运算符即可使其进入map / hash。