ZetCode

Qt5 中的容器

最后修改于 2023 年 10 月 18 日

在 Qt5 教程的这一部分,我们将讨论 Qt5 中的容器。以下容器被提及:QVector, QList, QStringList, QSetQMap

容器是通用类,用于将给定类型的项目存储在内存中。C++ 有标准模板库 (STL),它有自己的容器。在 Qt 中,我们可以使用 Qt 容器或 STL 容器。

有两种容器:顺序容器和关联容器。顺序容器将项目一个接一个地存储,而关联容器存储键值对。QListQVectorQLinkedList 属于顺序容器;QMapQHash 是关联容器的例子。

由于在本章中我们创建命令行程序,我们不需要 Qt GUI 模块。我们可以将 QT -= gui 声明添加到项目文件中。

Qt5 QVector

QVector 是一个提供动态数组的模板类。它将其项目存储在相邻的内存位置,并提供基于索引的快速访问。对于大型向量,插入操作较慢,建议使用 QList 容器。

myvector.cpp
#include <QVector>
#include <QTextStream>

int main(void) {

    QTextStream out(stdout);

    QVector<int> vals = {1, 2, 3, 4, 5};

    out << "The size of the vector is: " << vals.size() << endl;

    out << "The first item is: " << vals.first() << endl;
    out << "The last item is: " << vals.last() << endl;

    vals.append(6);
    vals.prepend(0);

    out << "Elements: ";

    for (int val : vals) {

        out << val << " ";
    }

    out << endl;

    return 0;
}

该示例使用整数向量。

QVector<int> vals = {1, 2, 3, 4, 5};

创建了一个整数向量。

out << "The size of the vector is: " << vals.size() << endl;

size 方法给出向量的大小——向量中的项目数。

out << "The first item is: " << vals.first() << endl;

第一个项目使用 first 方法检索。

out << "The last item is: " << vals.last() << endl;

向量的最后一个项目使用 last 方法找到。

vals.append(6);

append 方法将值插入到向量的末尾。

vals.prepend(0);

prepend 方法将值插入到向量的开头。

for (int val : vals) {

    out << val << " ";
}

我们在 for 循环中遍历向量并打印其内容。

$ ./myvector
The size of the vector is: 5
The first item is: 1
The last item is: 5
Elements: 0 1 2 3 4 5 6

Qt5 QList

QList 是用于创建元素列表的容器。它类似于 QVector。它存储一个值列表,并提供基于索引的快速访问以及快速插入和删除。它是 Qt 中最常用的容器之一。

mylist.cpp
#include <QTextStream>
#include <QList>
#include <algorithm>

int main(void) {

    QTextStream out(stdout);

    QList<QString> authors = {"Balzac", "Tolstoy",
        "Gulbranssen", "London"};

    for (int i=0; i < authors.size(); ++i) {

        out << authors.at(i) << endl;
    }

    authors << "Galsworthy" << "Sienkiewicz";

    out << "***********************" << endl;

    std::sort(authors.begin(), authors.end());

    out << "Sorted:" << endl;
    for (QString author : authors) {

        out << author << endl;
    }

    return 0;
}

该示例展示了 QList 容器。

QList<QString> authors = {"Balzac", "Tolstoy",
    "Gulbranssen", "London"};

创建了一个 QList 容器。它存储作家的名字。

for (int i=0; i < authors.size(); ++i) {

    out << authors.at(i) << endl;
}

在 for 循环中,我们遍历容器并打印其元素。at 方法返回给定索引处的项目。

authors << "Galsworthy" << "Sienkiewicz";

<< 运算符用于将两个新项目插入到列表中。

std::sort(authors.begin(), authors.end());

std::sort 方法按升序对列表进行排序。

out << "Sorted:" << endl;
for (QString author : authors) {

    out << author << endl;
}

现在我们打印排序后的列表。

$ ./mylist
Balzac
Tolstoy
Gulbranssen
London
***********************
Sorted:
Balzac
Galsworthy
Gulbranssen
London
Sienkiewicz
Tolstoy

QStringList

QStringList 是一个方便的容器,提供字符串列表。它具有基于索引的快速访问以及快速插入和删除。

mystringlist.cpp
#include <QTextStream>
#include <QList>

int main(void) {

    QTextStream out(stdout);

    QString string = "coin, book, cup, pencil, clock, bookmark";
    QStringList items = string.split(",");
    QStringListIterator it(items);

    while (it.hasNext()) {

        out << it.next().trimmed() << endl;
    }

    return 0;
}

在本例中,我们从一个字符串创建一个字符串列表,并将元素打印到控制台中。

QString string = "coin, book, cup, pencil, clock, bookmark";
QStringList items = string.split(",");

QStringsplit 方法根据提供的分隔符将字符串分割成子字符串。子字符串以列表形式返回。

QStringListIterator it(items);

QStringListIteratorQStringList 提供 Java 风格的 const 迭代器。

while (it.hasNext()) {

    out << it.next().trimmed() << endl;
}

使用创建的迭代器,我们将列表的元素打印到终端。trimmed 方法修剪字符串元素中的空格。

$ ./mystringlist
coin
book
cup
pencil
clock
bookmark

Qt5 QSet

QSet 提供具有快速查找的单值数学集合。这些值以未指定的顺序存储。

myset.cpp
#include <QSet>
#include <QList>
#include <QTextStream>
#include <algorithm>

int main(void) {

    QTextStream out(stdout);

    QSet<QString> cols1 = {"yellow", "red", "blue"};
    QSet<QString> cols2 = {"blue", "pink", "orange"};

    out << "There are " << cols1.size() << " values in the set" << endl;

    cols1.insert("brown");

    out << "There are " << cols1.size() << " values in the set" << endl;

    cols1.unite(cols2);

    out << "There are " << cols1.size() << " values in the set" << endl;

    for (QString val : cols1) {
        out << val << endl;
    }

    QList<QString> lcols = cols1.values();
    std::sort(lcols.begin(), lcols.end());

    out << "*********************" << endl;
    out << "Sorted:" << endl;

    for (QString val : lcols) {
        out << val << endl;
    }

   return 0;
}

QSet 用于在本例中存储颜色。指定一个颜色值多次是没有意义的。

QSet<QString> cols1 = {"yellow", "red", "blue"};
QSet<QString> cols2 = {"blue", "pink", "orange"};

我们有两个颜色值集合。蓝色位于两个集合中。

out << "There are " << cols1.size() << " values in the set" << endl;

size 方法返回集合的大小。

cols1.insert("brown");

我们使用 insert 方法向集合添加一个新值。

cols1.unite(cols2);

unite 方法执行两个集合的并集。cols1 集合将包含来自 cols2 集合的所有未存在的项目;在本例中,除了蓝色之外的所有颜色。

for (QString val : cols1) {

    out << val << endl;
}

通过 for 循环,我们打印 cols1 集合中的所有项目。

QList<QString> lcols = cols1.values();
std::sort(lcols.begin(), lcols.end());

不支持集合的排序。我们可以从集合中创建一个列表并对其进行排序。values 方法返回一个包含集合中元素的新的 QListQList 中元素的顺序是未定义的。

$ ./myset
There are 3 values in the set
There are 4 values in the set
There are 6 values in the set
pink
orange
brown
blue
yellow
red
*********************
Sorted:
blue
brown
orange
pink
red
yellow

Qt5 QMap

QMap 是一个关联数组(字典),它存储键值对。它提供了与键关联的值的快速查找。

myqmap.cpp
#include <QTextStream>
#include <QMap>

int main(void) {

    QTextStream out(stdout);

    QMap<QString, int> items = { {"coins", 5}, {"books", 3} };

    items.insert("bottles", 7);

    QList<int> values = items.values();

    out << "Values:" << endl;

    for (int val : values) {
        out << val << endl;
    }

    QList<QString> keys = items.keys();

    out << "Keys:" << endl;
    for (QString key : keys) {
        out << key << endl;
    }

    QMapIterator<QString, int> it(items);

    out << "Pairs:" << endl;

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

    return 0;
}

在本例中,我们有一个字典,我们将字符串键映射到整数值。

QMap<QString, int> items = { {"coins", 5}, {"books", 3} };

创建了一个 QMap。它有两个对。

items.insert("bottles", 7);

使用 insert 方法插入一个新对。

QList<int> values = items.values();

out << "Values:" << endl;

for (int val : values) {
    out << val << endl;
}

我们获取字典的所有值并将它们打印到控制台。values 方法返回一个地图值列表。

QList<QString> keys = items.keys();

out << "Keys:" << endl;
for (QString key : keys) {
    out << key << endl;
}

同样,我们打印字典的所有键。keys 方法返回一个包含字典中所有键的列表。

QMapIterator<QString, int> it(items);

QMapIteratorQMap 的 Java 风格迭代器。它可以用于迭代地图的元素。

while (it.hasNext()) {

    it.next();
    out << it.key() << ": " << it.value() << endl;
}

在迭代器的帮助下,我们遍历地图的所有元素。key 方法返回当前键,而 value 方法返回当前值。

$ ./myqmap
Values:
3
7
5
Keys:
books
bottles
coins
Pairs:
books: 3
bottles: 7
coins: 5

自定义类排序

在下面的例子中,我们将对自定义类的对象进行排序 QList

book.h
class Book {

    public:
        Book(QString, QString);
        QString getAuthor() const;
        QString getTitle() const;

    private:
        QString author;
        QString title;
};

这是我们自定义 Book 类的头文件。

book.cpp
#include <QString>
#include "book.h"

Book::Book(QString auth, QString tit) {

    author = auth;
    title = tit;
}

QString Book::getAuthor() const {

    return author;
}

QString Book::getTitle() const {

    return title;
}

这是 Book 类的实现;我们有两个访问器方法。

sortcustomclass.cpp
#include <QTextStream>
#include <QList>
#include <algorithm>
#include "book.h"

bool compareByTitle(const Book &b1, const Book &b2) {

  return b1.getTitle() < b2.getTitle();
}

int main(void) {

    QTextStream out(stdout);

    QList<Book> books = {

        Book("Jack London", "The Call of the Wild"),
        Book("Honoré de Balzac", "Father Goriot"),
        Book("Leo Tolstoy", "War and Peace"),
        Book("Gustave Flaubert", "Sentimental education"),
        Book("Guy de Maupassant", "Une vie"),
        Book("William Shakespeare", "Hamlet")
    };

    std::sort(books.begin(), books.end(), compareByTitle);

    for (Book book : books) {
        out << book.getAuthor() << ": " << book.getTitle() << endl;
    }

    return 0;
}

在本例中,我们创建了几个 book 对象,并使用 std::sort 算法对它们进行排序。

bool compareByTitle(const Book &b1, const Book &b2) {

  return b1.getTitle() < b2.getTitle();
}

compareByTitle 是排序算法使用的比较函数。

std::sort(books.begin(), books.end(), compareByTitle);

std::sort 算法按书的标题对列表中的书进行排序。

$ ./sortcustomclass
Honoré de Balzac: Father Goriot
William Shakespeare: Hamlet
Gustave Flaubert: Sentimental education
Jack London: The Call of the Wild
Guy de Maupassant: Une vie
Leo Tolstoy: War and Peace

在本章中,我们使用了 Qt 的容器。