1. QMap深度解析

(1)QMap是一个以升序键顺序存储键值对的数据结构

  ①QMap原型为 class QMap<K, T>模板

  ②QMap中的键值对根据Key进行了排序

  ③QMap中的Key类型必须重载operator< 。(即“小于”操作符)

(2)QMap使用示例1

QMap<QString, int> map;

//注意插入时是无序的
map.insert();
map.insert();
map.insert();

; i<; i++)
{
    //通过键取值
    qDebug() << map.value("key " + QString::number(i));
}

//注意map中的key会被升序排序
QList<QString> list = map.keys();

; i<list.count(); i++)
{
    qDebug() << list[i];
}

(3)QMap使用示例2:用数组方式迭代器方式访问

QMap<QString, int> map;

//以数组方式存取,注意输入时为无序的
map[;
map[;
map[;

; i<; i++)
{
    //以数组方式取值
    qDebug() << map["key " + QString::number(i)];
}

//it可看到一个指针,指向第1个元素之前。
QMapIterator<QString, int> it(map);

while(it.hasNext())
{
    it.next();
    qDebug() << it.key() << " : " << it.value();
}

(4)QMap的注意事项

  ①通过Key获取Value时:

    A.当Key存在时:返回对应的Value;

    B.当Key不存在时:返回值类型所对应的“零”值

  ②插入键值对时

    A.当Key存在时更新Value的值

    B.当Key不存在时插入新的键值对

【编程实验】QMap使用体验

#include <QCoreApplication>
#include <QMap>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QMap<QString, int> map;

    //插入键值对,注意,插入操作是无序的,存入后会被自动升序排序。
    map.insert();
    map.insert();
    map.insert();

    //取出所有的键(经过排序的)
    QList<QString> kList = map.keys();

    ; i<kList.count(); i++)
    {
        qDebug() << kList[i];//注意,输出元素是升序排列的
    }

    //取出所有的值(根据key排序过的顺序)
    QList<int> vList = map.values();

    ; i<vList.count(); i++)
    {
        qDebug() << vList[i];//注意,输出元素是根据key排序过的
    }

    //通过迭代器遍历
    QMapIterator<QString, int> it(map); //it指针第1个元素之前的位置

    while(it.hasNext())
    {
        it.next();
        qDebug() << it.key() << " : " << it.value();
    }

    return a.exec();
}
/*输出结果:
"key 0"
"key 1"
"key 2"
0
1
2
"key 0"  :  0
"key 1"  :  1
"key 2"  :  2
*/

2. QHash深度解析

(1)QHash是Qt中的哈希数据结构

  ①QHash原型为class QHash<K, T>模板

  ②QHash中的键值对在内部无序排列。注意QMap是升序排序的

  ③QHash的Key类型必须重载operator==。(即“相等”操作符)

  ④QHash中的Key对象必须重载全局哈希函数qHash()

(2)QHash使用示例

QHash<QString, int> hash;

//以数组方式存取,注意输入时为无序的
hash[;
hash[;
hash[;

QHash<QString, int>::const_iterator i; //const_iterator为内部类

for(int i=hash.constBegin(); i!= hash.constEnd(); ++i)
{
    qDebug() << i.key() << " :" << i.value();
}

//it可看到一个指针,指向第1个元素之前。
QMapIterator<QString, int> it(map);

while(it.hasNext())
{
    it.next();
    qDebug() << it.key() << " : " << it.value();
}

【编程实验】QHash使用体验

#include <QCoreApplication>
#include <QHash>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QHash<QString, int> hash;

    //插入键值对,注意,插入操作是无序的,但存入后不会自动排序。
    hash.insert();
    hash.insert();
    hash.insert();

    //取出所有的键
    QList<QString> kList = hash.keys();

    ; i<kList.count(); i++)
    {
        qDebug() << kList[i];
    }

    //取出所有的值
    QList<int> vList = hash.values();

    ; i<vList.count(); i++)
    {
        qDebug() << vList[i];
    }

    hash[; //通过数组方式存入键值对

    //通过迭代器遍历
    QHash<QString, int>::const_iterator it;

    for(it = hash.constBegin(); it != hash.constEnd(); ++it)
    {
        qDebug() << it.key() << " : " << it.value();
    }

    return a.exec();
}
/*输出结果:
"key 2"
"key 0"
"key 1"
2
0
1
"key 2"  :  2
"key 4"  :  4
"key 0"  :  0
"key 1"  :  1
*/

(3)QMap和QHash接口的比较

QMap

QHash

接口

接口相同,可直接替换使用

查找速度

较慢

占用存储空间

较小

元素存储

以Key的升序存领储

任意的方式

键类型必须重载的函数

Operator<()函数

Operator==()和qHash(Key)函数

【编程实验】文本编辑器程序中的文件后缀名映射

//处理后缀的代码

QString MainWindow::showFileDialog(QFileDialog::AcceptMode mode, QString title)
{
    QString ret = "";
    QFileDialog fd(this);
    QStringList filters;
    QMap<QString, QString> map;
    ] =
    {
        {"Text(*.txt)",    ".txt"},
        {"All Files(*.*)", "*"   },
        {NULL,             NULL}
    };

    ; filterArray[i][] != NULL; i++)
    {
        filters.append(filterArray[i][]);
        map.insert(filterArray[i][], filterArray[i][]);
    }

    fd.setWindowTitle(title);
    fd.setAcceptMode(mode); //QFileDialog::AcceptOpen或AcceptSave
    fd.setNameFilters(filters);

    if(mode == QFileDialog::AcceptOpen)
    {
        fd.setFileMode(QFileDialog::ExistingFile); //打开文件必须存在!
    }

    if(fd.exec() == QFileDialog::Accepted)
    {
        ret = fd.selectedFiles()[];

        //Qt5中ret返回的是完整的路径名,含后缀。因此,后面的if块可省略,但Qt4可能
        //会返回不带后缀的文件名,当保存文件时,须手动加上去。
        if(mode == QFileDialog::AcceptSave)
        {
            QString postfix = map[fd.selectedNameFilter()];
            if((postfix != "*") && !ret.endsWith(postfix))
            {
                ret = ret + postfix;
            }
        }
    }

    return ret;
}

//完整的MainWindowSlots.cpp代码

//该文件MainWindowSlots.cpp与MainWindowUI.cpp的分离
//体现了界面和功能代码分离的思想
#include "MainWindow.h"
#include <QMessageBox>
#include <QFile>
#include <QTextStream>
#include <QMap>
#include <QDebug>

void MainWindow::showErrorMessage(QString message)
{
    QMessageBox msg(this);

    msg.setWindowTitle("Erro");
    msg.setText(message);
    msg.setIcon(QMessageBox::Critical);
    msg.setStandardButtons(QMessageBox::Ok);

    msg.exec();
}

int MainWindow::showQueryMessage(QString message)
{
    QMessageBox msg(this);

    msg.setWindowTitle("Query");
    msg.setText(message);
    msg.setIcon(QMessageBox::Question);
    msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);

    return msg.exec();
}

QString MainWindow::showFileDialog(QFileDialog::AcceptMode mode, QString title)
{
    QString ret = "";
    QFileDialog fd(this);
    QStringList filters;
    QMap<QString, QString> map;
    ] =
    {
        {"Text(*.txt)",    ".txt"},
        {"All Files(*.*)", "*"   },
        {NULL,             NULL}
    };

    ; filterArray[i][] != NULL; i++)
    {
        filters.append(filterArray[i][]);
        map.insert(filterArray[i][], filterArray[i][]);
    }

    fd.setWindowTitle(title);
    fd.setAcceptMode(mode); //QFileDialog::AcceptOpen或AcceptSave
    fd.setNameFilters(filters);

    if(mode == QFileDialog::AcceptOpen)
    {
        fd.setFileMode(QFileDialog::ExistingFile); //打开文件必须存在!
    }

    if(fd.exec() == QFileDialog::Accepted)
    {
        ret = fd.selectedFiles()[];

        //Qt5中ret返回的是完整的路径名,含后缀。因此,后面的if块可省略,但Qt4可能
        //会返回不带后缀的文件名,当保存文件时,须手动加上去。
        if(mode == QFileDialog::AcceptSave)
        {
            QString postfix = map[fd.selectedNameFilter()];
            if((postfix != "*") && !ret.endsWith(postfix))
            {
                ret = ret + postfix;
            }
        }
    }

    return ret;
}

void MainWindow::preEditorChanged()
{
    if (m_isTextChanged)
    {
        int r = showQueryMessage("Do you want to save the changes to file?");

        switch(r)
        {
        case QMessageBox::Yes:
            saveCurrentData(m_filePath);
            break;
        case QMessageBox::No:
            m_isTextChanged = false;
            break;
        case QMessageBox::Cancel:
            break;
        }
    }
}

void MainWindow::onFileNew()
{
    preEditorChanged();

    if(!m_isTextChanged)
    {
        mainEditor.clear();

        setWindowTitle("NotePad - [ New ]");

        m_filePath = "";

        m_isTextChanged = false;
    }
}

void MainWindow::onFileOpen()
{
    preEditorChanged();

    if( !m_isTextChanged)
    {
        QString path = showFileDialog(QFileDialog::AcceptOpen, "Open");

        if( path != "")
        {
            QFile file(path);

            if (file.open(QIODevice::ReadOnly | QIODevice::Text))
            {
                mainEditor.setPlainText(QString(file.readAll()));

                file.close();

                m_filePath = path; //记录当前打开的文件路径和文件名

                m_isTextChanged = false;

                setWindowTitle("NotePad - [" + m_filePath + "]");
            }
            else
            {
                showErrorMessage(QString("Open file Error!\n\n") + "\"" + path + "\"");
            }
        }
    }
}

QString MainWindow::saveCurrentData(QString path, QString title)
{
    QString ret = path;
    if (ret =="")
    {
        //执行下面语句时,用户可以点击“取消”,此时ret返回""
        ret = showFileDialog(QFileDialog::AcceptSave, title);
    }

    if (ret != "")
    {
        QFile file(ret);

        if (file.open(QIODevice::WriteOnly | QIODevice::Text))
        {
            QTextStream out(&file);

            out << mainEditor.toPlainText();

            file.close();

            setWindowTitle("NotePad - [" + ret + "]");

            m_isTextChanged = false; //己保存
        }
        else
        {
            showErrorMessage(QString("Save file Error!\n\n") + "\"" + m_filePath + "\"");
            ret =""; //保存失败时
        }
    }

    return ret;
}

void MainWindow::onFileSave()
{
    QString path = saveCurrentData(m_filePath, "Save");

    if( path != "" )
    {
        m_filePath = path;
    }
}

void MainWindow::onFileSaveAs()
{
    QString path = saveCurrentData(m_filePath, "Save As");

    if( path != "" )
    {
        m_filePath = path;
    }
}

void MainWindow::onTextChanged()
{
    if( !m_isTextChanged )
    {
        setWindowTitle("*" + windowTitle());
    }

    m_isTextChanged = true;
    //qDebug()<< "onTextChanged()";
}

3. 小结

(1)Qt中提供了用于存储键值对的类模板

(2)QHash和QMap遵循相同的使用接口

(3)QHash的查找速度快于QMap

(4)QMap需要的内存空间低于QHash

(5)QHash对于Key类型的要求高于QMap。(QHash要求key类型操作两个操作符函数)

第37课 深度解析QMap与QHash的更多相关文章

  1. Kafka深度解析

    本文转发自Jason’s Blog,原文链接 http://www.jasongj.com/2015/01/02/Kafka深度解析 背景介绍 Kafka简介 Kafka是一种分布式的,基于发布/订阅 ...

  2. 深度解析SDN——利益、战略、技术、实践(实战派专家力作,业内众多专家推荐)

    深度解析SDN——利益.战略.技术.实践(实战派专家力作,业内众多专家推荐) 张卫峰 编   ISBN 978-7-121-21821-7 2013年11月出版 定价:59.00元 232页 16开 ...

  3. mybatis 3.x源码深度解析与最佳实践(最完整原创)

    mybatis 3.x源码深度解析与最佳实践 1 环境准备 1.1 mybatis介绍以及框架源码的学习目标 1.2 本系列源码解析的方式 1.3 环境搭建 1.4 从Hello World开始 2 ...

  4. Kafka深度解析(如何在producer中指定partition)(转)

    原文链接:Kafka深度解析 背景介绍 Kafka简介 Kafka是一种分布式的,基于发布/订阅的消息系统.主要设计目标如下: 以时间复杂度为O(1)的方式提供消息持久化能力,即使对TB级以上数据也能 ...

  5. 《SEO深度解析——全面挖掘搜索引擎优化的核心秘密》

    <SEO深度解析——全面挖掘搜索引擎优化的核心秘密> 基本信息 作者: 痞子瑞 出版社:电子工业出版社 ISBN:9787121224041 上架时间:2014-2-28 出版日期:201 ...

  6. linux ssh使用深度解析(key登录详解)

    linux ssh使用深度解析(key登录详解) SSH全称Secure SHell,顾名思义就是非常安全的shell的意思,SSH协议是IETF(Internet Engineering Task ...

  7. 程序员收藏必看系列:深度解析MySQL优化(二)

    程序员收藏必看系列:深度解析MySQL优化(一) 性能优化建议 下面会从3个不同方面给出一些优化建议.但请等等,还有一句忠告要先送给你:不要听信你看到的关于优化的“绝对真理”,包括本文所讨论的内容,而 ...

  8. Flink 源码解析 —— 深度解析 Flink 是如何管理好内存的?

    前言 如今,许多用于分析大型数据集的开源系统都是用 Java 或者是基于 JVM 的编程语言实现的.最着名的例子是 Apache Hadoop,还有较新的框架,如 Apache Spark.Apach ...

  9. Flink 源码解析 —— 深度解析 Flink 序列化机制

    Flink 序列化机制 https://t.zsxq.com/JaQfeMf 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac 上搭 ...

随机推荐

  1. 连接输出 如果存在在php中多次echo输出js的时候

  2. Java中,方法的重写、重载的区别,以及多态的实例

    首先我们要明白什么是重写和重载 重写(override):子类方法覆盖了父类的方法.    (类与类之间继承的关系) 例:父类代码 public class Deng { public void Qi ...

  3. highCharts提示框不显示的问题

    使用HighCharts插件进行数据展示的时候,鼠标放在数据处没有提示框,或者只有头尾2个提示框,其他提示框不显示,为什么会这样? 1.查看是否使用了tooltip属性,该属性的enabled默认为t ...

  4. 【blade的UI设计】理解前端MVC与分层思想

    前言 最近校招要来了,很多大三的同学一定按捺不住心中的焦躁,其中有期待也有彷徨,或许更多的是些许担忧,最近在开始疯狂的复习了吧 这里小钗有几点建议给各位: ① 不要看得太重,关心则乱,太紧张反而表现不 ...

  5. gulp安装说明

    1.安装node-v6.3.0-x64,安装成功后再点击node-v6.3.0-x64卸载(点击remove). 2.安装node-v4.4.7-x64. 3.打开cmd命令行,输入node -v,查 ...

  6. UITableViewHeaderFooterView的封装

    UITableViewHeaderFooterView的封装 特点 1. 封装的 UITableViewHeaderFooterView 能够让用户更好的自定义自己的 headerView; 2. 封 ...

  7. 网页返回顶部之animate方法

    点击返回顶部按钮,页面滑动形式回到顶部! HTML代码: <div id="ctop">回到<br>顶部</div> CSS代码: #ctop{ ...

  8. android 性能分析案例

    本章以实际案例分析在android开发中,性能方面的优化和处理.设计到知识点有弱引用,memory monitor,Allocation Tracker和leakcanary插件. 1.测试demo ...

  9. Android性能优化之内存优化练习

    练习题目地址:https://github.com/lzyzsd/MemoryBugs 分析及优化过程如下: 问题1 静态变量引用activity 使用神器LeakCanary检查内存泄露问题 从图中 ...

  10. Xcode7--免证书真机调试

    Xcode7之前,想要真机调试,必须花99刀购买开发者账号,而且步骤繁琐,需要下载证书.随着Xcode7的推出,大幅度的简化了真机调试的步骤,对ios开发工作者和正在学习ios开发的众多码农们,可以说 ...