Qt开发总结(5)——Qt中的容器

C++的标准模板库(STL)中定义了一系列容器,并对应有若干容器类和操作容器用到的迭代器(这部分内容可参见本人博客《C++学习笔记——STL标准模板库》)。Qt自定义了几个容器类,这些容器类同样是基于模板的,可以实例化为具体的数据类型。相比于STL中的容器,Qt中的容器更加轻巧、安全和便于使用,而且进行了速度和存储优化,另外,它们还是线程安全的,可以作为只读容器被多个线程访问。

与STL类似,Qt的容器类分为顺序容器和关联容器。前者的数据结构是线性表,后者的数据结构是树。顺序容器类有QList,QLinkedList,QVector,QStack,QQueue;关联容器类包括QMap,QMultiMap,QHash,QMultiHash,Qset。同样使用迭代类访问容器中的数据项,Qt提供Java类型的迭代类和STL类型的迭代类。Java类型的迭代易于适用并提供高级功能,而STL类型的迭代效率则会更高一些。

容器

QList

Qlist是最常用的容器类,它存储一组类型为T的数据。其内核实现是用数组列表的方式进行存储的,这使得用下标方式获取某个值非常快。对Qlist进行增删改查的常用接口有:

接口

描述

insert()

插入数据

removeAt()

删除某个数据

removeFirst()

删除头

扫描二维码关注公众号,回复: 9657328 查看本文章

removeLast()

删除尾

repalce()

更改数据

move()

移动数据

swap()

交换数据

append

在头前增加数据

prepend

在尾后增加数据

at()

快速获取某位置数据,类似数据下标

isEmpty()

判断容器是否为空

size()

判断容器数据大小

QList<int> integerList;

QList<QDate> dateList;

QLinkedList

QLinkedList 是链表,很像QList,但是数据项不是用连续的内存存储的,它基于迭代器访问数据项,且插入和删除数据项的操作时间相同。除了不提供基于下标索引的数据项访问外,QLinkedList的其他接口函数与QList基本相同。

QLinkedList<int> integerList;

QLinkedList<QTime> timeList;

QVector

Qvector提供动态数组的功能,以下标索引访问数据。QVector与QList的函数接口几乎完全相同,但是由于QVector的数据项是连续存储的,在其头或者中间位置插入数据的效率可能会非常慢。

QVector<int> integerVector;

QVector<QString> stringVector;

QStack

QStack是类似于堆栈的后入先出LIFO容器类。它的基本接口是push()和pop()。

QStack<int> stack;
stack.push(1);
stack.push(2);
stack.push(3);
while (!stack.isEmpty())
     cout << stack.pop() << endl;

QQueue

Queue是类似于队列的先入先出FIFO容器类。它的基本接口是enqueue()和dequeue()。

QQueue<int> queue;
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
while (!queue.isEmpty())
    cout << queue.dequeue() << endl;

QSet

QSet是单个数据的集合。基于散列表,存储的数据顺序是不定的。查找值的速度非常快。

QSet<QString> set;
set.insert("one");
set.insert("three");
set.insert("seven");
if (!set.contains("ninety-nine"))

QMap

QMap<Key, T> 提供一个关联数组,一个键(key)映射到一个(key)。QMap存储数据是按照键的顺序,也即它会自动排序。如果我们不需要排序,QHash会更好用。

QMap<QString, int> map;
map["one"] = 1;
map["three"] = 3;
map["seven"] = 7;
map.insert("twelve", 12);
int num1 = map["thirteen"];
int num2 = map.value("thirteen");

QMultiMap

QMultiMap<Key, T> T是QMap的子类,用于处理多值映射(多个值对应一个键值)。注意,QMultiMap不提供[]操作符,可只用value和values获取值,返回值是QList<T>。

QMultiMap<QString, int> map1, map2, map3;
map1.insert("plenty", 100);
map1.insert("plenty", 2000);
// map1.size() == 2

map2.insert("plenty", 5000);
// map2.size() == 1

map3 = map1 + map2;
// map3.size() == 3

QList<int> values = map.values("plenty");
for (int i = 0; i < values.size(); ++i)
    cout << values.at(i) << endl;

QHash

QHash<Key, T>是基于散列表来实现字典功能的模板类,与QMap的用法和功能基本相同,但QHash查找速度更快,数据项不会自动排序。

QHash<QString, int> hash;
hash["one"] = 1;
hash["three"] = 3;
hash["seven"] = 7;
hash.insert("twelve", 12);
int num1 = hash["thirteen"];
int num2 = hash.value("thirteen");

QMultiHash

QMultiHash是QHash的子类,用于处理多值映射。其用法与QHash类似。同样,QMultiHash不提供[]操作符,可只用value和values获取值,返回值是QList<T>。

QMultiHash<QString, int> hash1, hash2, hash3;
hash1.insert("plenty", 100);
hash1.insert("plenty", 2000);
// hash1.size() == 2

hash2.insert("plenty", 5000);
// hash2.size() == 1

hash3 = hash1 + hash2;
// hash3.size() == 3

QList<int> values = hash.values("plenty");
for (int i = 0; i < values.size(); ++i)
    cout << values.at(i) << endl;

 

迭代器

Java类型迭代器

对于每个容器类都有两个Java类型迭代器,一个用于只读操作,另一个用于读写操作。

Containers

Read-only iterator

Read-write iterator

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<Key, T>

QMutableMapIterator<Key, T>

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

QHashIterator<Key, T>

QMutableHashIterator<Key, T>

对于像QList的顺序容器类,Java类型迭代器的指针不是指向一个数据项,而是在数据项之间。

QList<QString> list;
list << "A" << "B" << "C" << "D";
QListIterator<QString> i(list);
while (i.hasNext())
    qDebug() << i.next();

对于上述只读遍历,容器list作为参数传给迭代器i的构造函数,开始迭代器的指针指向list第一个数据项的前面(A的前面),调用hasNext()函数以判断迭代器后面是否还有数据项。如果有,就调用next跳过一个数据项,且next返回跳过去的那个数据项。也可以反向遍历:

QListIterator<QString> i(list);
i.toBack();
while (i.hasPrevious())
    qDebug() << i.previous();

常见的移动指针和读取数据的迭代器接口有:

Function

Behavior

toFront()

Moves the iterator to the front of the list (before the first item)

toBack()

Moves the iterator to the back of the list (after the last item)

hasNext()

Returns true if the iterator isn't at the back of the list

next()

Returns the next item and advances the iterator by one position

peekNext()

Returns the next item without moving the iterator

hasPrevious()

Returns true if the iterator isn't at the front of the list

previous()

Returns the previous item and moves the iterator back by one position

peekPrevious()

Returns the previous item without moving the iterator

 

上述为只读迭代器,若要对数据进行修改,则需要使用QMutableListIterator。如:

QMutableListIterator<int> i(list);
while (i.hasNext())
{
    if (i.next() > 128)
        i.setValue(128);
}

对于关联容器QMap<key T>,使用QMapIterator和QMutableMapIterator迭代器类。他们具有上表中所有的接口,并增加了key()和value()函数用以获取刚刚跳过的数据项的键和值。如果在多值容器中遍历,可以用findNext或findPrevious函数查找下一个或上一个值。

QMap<int, QWidget *> map;
QHash<int, QWidget *> hash;
QMapIterator<int, QWidget *> i(map);
while (i.hasNext())
{
    i.next();
    hash.insert(i.key(), i.value());
}
//if there are multi values
QMutableMapIterator<int, QWidget *> i(map);
while (i.findNext(widget))
    i.remove();

STL类型迭代器

STL迭代器与Qt和STL兼容,并且进行了速度优化。对于每个容器类都有两个STL类型迭代器,一个用于只读操作,另一个用于读写操作。若无须修改数据时一定要使用只读迭代器,因为它们速度更快。

Containers

Read-only iterator

Read-write iterator

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>::iterator

STL类型迭代器是数组的指针,所以可以只用++ -- += -=运算符移动位置用解除引用运算符*获取其值。与JAVA类型迭代器不同,STL类型迭代器直接指向数据项。

begin()函数使迭代器指向容器的第一个数据项,end()函数使函数指向一个虚拟的标识结尾的数据项。end()表示的数据项是无效的,一般用作循环结束的判断条件。

对于QList等顺序容器,其通常用法为:

QList<QString>::const_iterator i;
for (i = list.constBegin(); i != list.constEnd(); ++i)
    qDebug() << *i;

对于QMap等关联容器类,其通常用法为:

QMap<int, int> map;
  ...
QMap<int, int>::const_iterator i;
for (i = map.constBegin(); i != map.constEnd(); ++i)
    qDebug() << i.key() << ':' << i.value();

foreach关键字

这里还要提到上篇笔记QtGlobal头文件中定义了一个foreach关键字,其作用为遍历容器中所有的项。语法为:

foreach (variable, container)
         statement.

可以看到使用foreach比使用迭代器更加简洁,像是一个for循环,对于多值映射可以用两层foreach来实现。

QLinkedList<QString> list;
  ...
foreach (const QString &str, list)
    qDebug() << str;

QMap<QString, int> map;
  ...
foreach (const QString &str, map.keys())
    qDebug() << str << ':' << map.value(str);

QMultiMap<QString, int> map;
  ...
foreach (const QString &str, map.uniqueKeys()) 
{
    foreach (int i, map.values(str))
        qDebug() << str << ':' << i;
}

 

发布了76 篇原创文章 · 获赞 63 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/bjtuwayne/article/details/99339002