Qt学习之路25--QMap和QHash

版权声明:未经说明,禁止转载 https://blog.csdn.net/tqs_1220/article/details/82503275

在C++标准库中是有map容器的概念。

QMap

  • QMap是一个以升序键顺序存储键值对的数据结构
  • QMap原型为class QMap<key, value>
  • QMap中根据键值key进行的升序排序
  • QMap中key的类型必须要重载operator <操作符
  • QMap提供了一个从类项为key的键到类项为value的值的映射,通常所存储的数据类型是一个键对应一个值
  • 同时也支持一键多值的情况,用类QMultiMap可以实现。
  • 键值对都可以是任意类型
  • 可以定义迭代器指向每个键值对元素,可以理解成一个指针
  • 通过key获取value时:
    • 当key存在:返回对应的value
    • 当key不存在:返回value类型对应的“零值”
  • 插入键值对时:
    • 当key存在:更新value的值
    • 当key不存在:插入新的键值对

QHash

  • QHash是Qt中的哈希数据结构
  • QHash原型为class QHash<key, value>
  • QHash的键值对在内部无序排列
  • QHash中的key类型必须重载operator ==操作符
  • QHash中的key对象必须重载全局的qHash()函数
  • 此类维护一张哈希表,表的大小和数据项是自适应的
  • QHash是以任意的顺序存储的数据
  • 也是可以支持一键多值的,用类QMultiHash可以实现。
  • 键值对都可以是任意类型
  • QMap和QHash的接口相同,可直接替换使用
  • 可以很方便的根据设置的键来获取对应的值,查找效率高于QMap。
  • 迭代器it可以理解成一个指针,可以指向QMap对象的每个元素

哈希函数

  • 哈希函数是一个散列函数,其作用就是为了打乱输入规律
  • 哈希函数的输入域无穷,输出域(S域)有限
  • 通过哈希函数处理后,一个输入对应一个确定的输出
  • 存在哈希碰撞,即多个输入可能得到同一个输出
  • 由于输入域无穷,输出域有限,所以当有很多个不同输入时,得到的输出结果是均匀排布的
  • 哈希函数的输出值与输入规律无关
  • 输出域(S域)是均匀分布的,当对输出域每个值进行同一个值的模运算后其结果仍然均匀分布
  • 哈希表经典结构是数组加链表,比如数组大小为M,在对插入多个键值对进行哈希函数计算得到相当多的code码,执行code%M后所有的结果就会分布在0~M-1的位置,当发生哈希碰撞时就将重复的key值对应的value值使用链表将其挂接起来,每个位置后面挂接的链表的长度都是基本均匀的
  • 当需要扩容时根据扩大容量的倍数来决定复杂度,比如每次扩大2倍就是log2(N),但是现在存在各种优化方法,可以使得增删改查的复杂度都为O(1)

两者区别

  • QHash的查找速度明显快于QMap
    • 因为QHash的排布是通过调用qhash()这个全局哈希函数后获取的一个ID,通过调用函数后几乎能够立即获取这个ID,所以其定位速度十分快;而QMap因为是按键值升序排列,是使用二分查找方法进行查找的,速度会慢很多。
  • QHash占用的存储空间明显多于QMap,QHash的速度是利用空间换回来的。
  • QHash以任意的方式存储元素,因为是通过调用qHash函数获取ID,所以其排布是没有规律的;QMap以key的升序顺序存储的。
  • QHash的键类型必须提供operator ==()和qHash()函数;QMap的键类型必须提供operator<()函数。所以QMap在使用上也会相对简单一些。

QMap使用

void QMap_Test()
{
    QMap<QString, int> map;

    map.insert("key 2", 2);//插入键值对
    map.insert("key 1", 1);
    map.insert("key 0", 0);
    map.insert("key 5", 5);
    map.insert("key 6", 6);
    map.insert("key 4", 4);
    map.insert("key 3", 3);

    QList<QString> klist = map.keys();//一个QMap对象的键值对中的键保存在一个QList中

    for(int i = 0; i < klist.count(); i++)
    {
        qDebug() << klist[i];
    }

    QList<int> vlist = map.values();//一个QMap对象的键值对中的值保存在一个QList中

    for(int i = 0; i < vlist.count(); i++)
    {
        qDebug() << vlist[i];
    }

    QMapIterator<QString, int> it(map);//迭代器的使用,it一开始指向的是第0个元素之前的位置
    while(it.hasNext())//根据迭代器获取元素
    {
        it.next();
        qDebug() << it.key() << " : " << it.value();

    }
}

这里写图片描述
根据打印结果也可看出QMap的key是以升序进行排列。

QHash使用

void QHash_Test()
{
    QHash<QString, int> hash;

    hash.insert("key 1", 1);   
    hash.insert("key 58", 58);
    hash.insert("key 7", 7);
    hash.insert("key 45", 45);
    hash.insert("key 12", 12);
    hash.insert("key 56", 56);
    hash.insert("key 34", 34);

    QList<QString> klist = hash.keys();
    for(int i = 0; i < klist.count(); i++)
    {
        qDebug() << klist[i];
    }

    QList<int> vlist = hash.values();
    for(int i = 0; i < vlist.count(); i++)
    {
        qDebug() << vlist[i];
    }

    hash["key 44"] = 44;//通过下标方式插入
    QHash<QString, int>::const_iterator it;//迭代器的使用,it一开始指向的是第0个元素之前的位置
    for(it = hash.constBegin(); it != hash.constEnd(); ++it)
    {
        qDebug() << it.key() << " : " << it.value();
    }
}

这里写图片描述
根据结果也可以看出QHash对键值对的排列是乱序的,既不是升序也不是插入时的顺序。

QMap和QHash的接口函数

  • iterator begin () 返回指向第0位置元素的迭代器
  • const_iterator begin () const 功能同上
  • void clear () 清空所有元素
  • const_iterator constBegin () const 返回指向第0位置元素的const类型的迭代器
  • const_iterator constEnd () const 返回指向最后元素的下一个假想位置的const类型的迭代器
  • const_iterator constFind ( const Key & key ) const 返回键key对应元素位置的const类型的迭代器
  • bool contains ( const Key & key ) const 如果存在key对应的键值对,返回true,否则返回false
  • int count ( const Key & key ) const 返回与Key关联的键值对的数目
  • bool empty () const 是否为空
  • iterator erase ( iterator pos ) 清除pos指向的元素
  • iterator find ( const Key & key ) 返回根据key查找得到的键值对的itreator
  • const_iterator find ( const Key & key ) const const版本
  • iterator insert ( const Key & key, const T & value ) 插入键值对,如果插入的key存在,则会替换原先的键值对;如果这个key关联多个value,那么最后插入的那个键值对将被覆盖
  • iterator insertMulti ( const Key & key, const T & value ) 可以使得一个key关联多个value
  • const Key key ( const T & value ) const 根据value获取第一个key
  • QList <Key> keys () const
  • QList <Key> keys ( const T & value ) const
  • int remove ( const Key & key )
  • int size () const
  • T take ( const Key & key )
  • std::map <Key,T> toStdMap () const
  • QList <Key> uniqueKeys () const
  • const T value ( const Key & key ) const
  • const T value ( const Key & key, const T & defaultValue ) const
  • QList <Key> values () const
  • QList <Key> values ( const Key & key ) const

为文件编辑器添加后缀名补齐功能

这里写图片描述
- 文件对话框代码参见https://blog.csdn.net/tqs_1220/article/details/82469520
- 定义一个二维数组描述需要过滤的文件类型
- 将过滤类型添加到QStringList中并将需要过滤的文件类型通过setFilters设置到文件对话框
- 将过滤类型和后缀名作为键值对添加到QMap对象
- 当保存文件时检查文件名是否带有后缀

小结:

  • Qt中提供了用于存储键值对的类模板
  • QHash和QMap遵循相同的接口
  • QHash的查找速率快于QMap
  • QMap需要的内存空间小于QHash
  • QHash对于key类型的要求高于QMap

猜你喜欢

转载自blog.csdn.net/tqs_1220/article/details/82503275
今日推荐