1. 程式人生 > >Qt容器(QMap/QHash 等)使用詳解

Qt容器(QMap/QHash 等)使用詳解

一、Qt容器的遍歷器

Qt 的容器類提供了兩種風格的遍歷器:Java 風格和 STL 風格。

每一種容器都有兩種 Java 風格的遍歷器:一種提供只讀訪問,一種提供讀寫訪問:

容器

只讀遍歷器

讀寫遍歷器

QList<T>,QQueue<T>

QListIterator<T>

QMutableListIterator<T>

QLinkedList<T>

QLinkedListIterator<T>

QMutableLinkedListIterator<T>

QVector<T>,QStack<T>

QVectorIterator<T>

QMutableVectorIterator<T>

QSet<T>

QSetIterator<T>

QMutableSetIterator<Key,T>

QMap<Key, T>,QMultiMap<Key, T>

QMapIterator<Key,T>

QMutableMapIterator<Key,T>

QHash<Key, T>,QMultiHash<Key, T>

QHashIterator<Key,T>

QMutableHashIterator<Key,T>

STL 風格的遍歷器

STL 風格的遍歷器從 Qt 2.0 就開始提供。這種遍歷器能夠相容 Qt 和 STL 的通用演算法,並且為速度進行了優化。同 Java 風格遍歷器類似,Qt 也提供了兩種 STL 風格的遍歷器:一種是隻讀訪問,一種是讀寫訪問。我們推薦儘可能使用只讀訪問,因為它們要比讀寫訪問的遍歷器快一些。

容器

只讀遍歷器

讀寫遍歷器

QList<T>,QQueue<T>

QList<T>::const_iterator

QList<T>::iterator

QLinkedList<T>

QLinkedList<T>::const_iterator

QLinkedList<T>::iterator

QVector<T>,QStack<T>

QVector<T>::const_iterator

QVector<T>::iterator

QSet<T>

QSet<T>::const_iterator

QSet<T>::iterator

QMap<Key, T>,QMultiMap<Key, T>

QMap<Key, T>::const_iterator

QMap<Key, T>::iterator

QHash<Key, T>,QMultiHash<Key, T>

QHash<Key, T>::const_iterator

QHash<Key, T>::iter

二、QMap和QHash的對比分析

QMap和QHash的介面相同,可直接替換使用,它們之間的差異如下:

(1)、QHash的查詢速度明顯快於QMap

(2)、QHash佔用的儲存空間明顯多於QMap

(3)、QHash以任意的方式儲存元素

(4)、QMap以Key順序儲存元素

(5)、QHash如果使用自定義型別作為主鍵,QHash的鍵型別必須提供operator == () 和 qHash(key)函式

(6)、QMap如果使用自定義型別作為主鍵,QMap的鍵型別必須提供operator <函式

三、使用例項

#include "mainwindow.h"
#include <QApplication>
#include <QMap>
#include <QHash>
#include <QDate>
#include <QDebug>

struct Student
{
    QString name;
    int no;

    bool operator <(const struct Student& other) const
    {
        if (name < other.name)
        {
            return true;
        }
        else if (name == other.name)
        {
            return no < other.no;
        }

        return false;
    }
};

class Employee
{
public:
    Employee() {}
    Employee(const QString &name, const QDate &dateOfBirth){myName = name;myDateOfBirth = dateOfBirth;}
    const QString name(){return myName;}
    const QDate dateOfBirth(){return myDateOfBirth;}

    inline bool operator==(const Employee &other) const
    {
        return (myName==other.myName && myDateOfBirth==other.myDateOfBirth);
    }
    //以下的寫法是錯誤的//error: passing 'const Employee' as 'this' argument of 'const QString Employee::name()' discards qualifiers
    /*inline bool operator==(const Employee &other) const
    {
        return myName == other.name()
               && myDateOfBirth == other.dateOfBirth();
    }*/

public:
    QString myName;
    QDate myDateOfBirth;
};

//以下的寫法是錯誤的://error: passing 'const Employee' as 'this' argument of 'const QString Employee::name()' discards qualifiers
/*inline uint qHash(const Employee &key)
{
    return qHash(key.name()) ^ key.dateOfBirth().day();
}*/

inline uint qHash(const Employee key)
{
    //^ -----按位異或(Xor)是一種可逆運算子,只有在兩個比較的位不同時其結果是1,否則結果為0。
    return qHash(key.myName) ^ key.myDateOfBirth.day();
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    //----------------Java 風格的遍歷器
    /*每一種容器都有兩種 Java 風格的遍歷器:一種提供只讀訪問,一種提供讀寫訪問:
    容器                                 只讀遍歷器                讀寫遍歷器
    QList<T>,QQueue<T>                  QListIterator<T>        QMutableListIterator<T>
    QLinkedList<T>                      QLinkedListIterator<T>  QMutableLinkedListIterator<T>
    QVector<T>,QStack<T>                QVectorIterator<T>      QMutableVectorIterator<T>
    QSet<T>                             QSetIterator<T>         QMutableSetIterator<T>
    QMap<Key, T>,QMultiMap<Key, T>      QMapIterator<T>         QMutableMapIterator<T>
    QHash<Key, T>,QMultiHash<Key, T>    QHashIterator<T>        QMutableHashIterator<T>
    */
    //----------------end Java 風格的遍歷器
    //------QMap
    QMap<int,QString> id2NameMap;
    id2NameMap.insert(2,"name2");
    id2NameMap.insert(1,"name1");
    id2NameMap.insert(3,"name3");
    qDebug()<<id2NameMap;
    //只讀遍歷器
    QMapIterator<int,QString> it1(id2NameMap);
    while (it1.hasNext())
    {
        it1.next();
        if(2 == it1.key())
        {
            qDebug() << it1.value();
        }
    }

    //讀寫遍歷器
    QMutableMapIterator<int,QString> mit1(id2NameMap);
    while (mit1.hasNext())
    {
        mit1.next();
        if(2 == mit1.key())
        {
            mit1.setValue("name2new");
            qDebug() << mit1.value();
        }
    }
    qDebug()<<id2NameMap;
    //------end QMap

    //----------------STL 風格的遍歷器
    /*STL 風格的遍歷器從 Qt 2.0 就開始提供。這種遍歷器能夠相容 Qt 和 STL 的通用演算法,並且為速度進行了優化。
     * 同 Java 風格遍歷器類似,Qt 也提供了兩種 STL 風格的遍歷器:一種是隻讀訪問,一種是讀寫訪問。
     * 我們推薦儘可能使用只讀訪問,因為它們要比讀寫訪問的遍歷器快一些。

    容器                                 只讀遍歷器                        讀寫遍歷器
    QList<T>,QQueue<T>                  QList<T>::const_iterator        QList<T>::iterator
    QLinkedList<T>                      QLinkedList<T>::const_iterator  QLinkedList<T>::iterator
    QVector<T>,QStack<T>                QVector<T>::const_iterator      QVector<T>::iterator
    QSet<T>                             QSet<T>::const_iterator         QSet<T>::iterator
    QMap<Key, T>,QMultiMap<Key, T>      QMap<Key, T>::const_iterator    QMap<Key, T>::iterator
    QHash<Key, T>,QMultiHash<Key, T>    QHash<Key, T>::const_iterator   QHash<Key, T>::iter
     */

    //------QHash
    QHash<int,QString> id2NameHash;
    id2NameHash.insert(2,"hashName2");
    id2NameHash.insert(1,"hashName1");
    id2NameHash.insert(3,"hashName3");
    qDebug()<<id2NameHash;
    //只讀遍歷器
    QHash<int,QString>::const_iterator rIt1;
    for (rIt1 = id2NameHash.begin(); rIt1 != id2NameHash.end(); ++rIt1)
    {
        if(2 == rIt1.key())
        {
            qDebug() << rIt1.value();
        }
    }
    //讀寫遍歷器
    QHash<int,QString>::iterator wIt1;
    for (wIt1 = id2NameHash.begin(); wIt1 != id2NameHash.end(); ++wIt1)
    {
        if(2 == wIt1.key())
        {
            //修改內容
            *wIt1 = "hashName2new";// 使用 * 運算子獲取遍歷器所指的元素
            qDebug() << wIt1.value();
        }
        else if(3 == wIt1.key())
        {
            //修改內容
            id2NameHash.insert(3,"hashName3new");
            qDebug() << wIt1.value();
        }
    }
    qDebug()<<id2NameHash;
    //------end QHash

    //----------------------自定義key型別
    //QHash的鍵型別必須提供operator == () 和 qHash(key)函式
    //QMap的鍵型別必須提供operator <

    //------自定義 QMap的Key型別
    QMap<Student,QString> key2NameMap;
    Student tmp;
    tmp.no = 2;
    tmp.name = "name2";
    key2NameMap.insert(tmp,"name2");
    tmp.no = 1;
    tmp.name = "name1";
    key2NameMap.insert(tmp,"name1");
    tmp.no = 3;
    tmp.name = "name3";
    key2NameMap.insert(tmp,"name3");
//    qDebug()<<key2NameMap;

    Student find;
    find.no = 2;
    find.name = "name2";
    QMap<Student,QString>::iterator cusIt1 = key2NameMap.find(find);
    if(cusIt1 != key2NameMap.end())
    {
        qDebug()<<"I can find";
    }
    else
    {
        qDebug()<<"I can not find";
    }
    //------end 自定義 QMap的Key型別

    //------自定義 QHash的Key型別
    QHash<Employee,QString> customHash;
    customHash.insert(Employee("name1", QDate(2018,10,21)),"name1");
    customHash.insert(Employee("name3", QDate(2018,10,23)),"name3");
    customHash.insert(Employee("name2", QDate(2018,10,22)),"name2");
    customHash.insert(Employee("name7", QDate(2018,10,27)),"name7");
    //只讀遍歷器
    QHash<Employee,QString>::const_iterator rIt2;
    for (rIt2 = customHash.begin(); rIt2 != customHash.end(); ++rIt2)
    {
        qDebug() << rIt2.key().myName << ":" << rIt2.value();
    }
    //------end 自定義 QHash的Key型別


    MainWindow w;
    w.show();

    return a.exec();
}