Qt提供了哪些容器类

Qt 提供了丰富的容器类,这些容器类主要用于存储和管理数据,按照其内部组织结构和功能特性,大致可分为顺序容器和关联容器两大类:顺序容器:

QList - 动态数组,支持快速的头部和尾部插入删除操作,以及通过索引访问元素。QVector - 类似于QList,但内部实现保证了元素在内存中连续存储,对于大数据量并且频繁随机访问时,可能有更好的性能表现。QLinkedList - 双向链表,支持高效地在列表中间进行插入和删除操作,但不支持通过索引直接访问元素。QStack - 后进先出(LIFO)栈容器。QQueue - 先进先出(FIFO)队列容器。

关联容器: 6. QMap - 键值对映射容器,键值对按键自动排序。 7. QHash - 哈希表实现的键值对容器,提供常数时间复杂度的快速查找能力。 8. QSet - 集合容器,只包含唯一元素,不存储值对应的键。

另外还有一些特殊用途的容器: 9. QStringList - 字符串列表容器,实际上是QList的便捷版本,专用于存储字符串列表。 10. QByteArray - 字节数组容器,用于存储二进制数据。

以上容器类都是模板类,可以根据需要存储任何兼容类型的对象,并且它们在设计上力求简化接口、提高跨平台兼容性和线程安全性。相较于C++标准模板库(STL),Qt的容器类通常被认为更适合于GUI开发环境,尤其是考虑到多线程同步问题时。

QList 详细介绍

QList详细介绍

QList是Qt框架中的一个重要的泛型容器类,它是动态数组的实现,但是它的内部实现并不是简单的连续内存区域,而是根据元素大小和数量选择最优的存储策略(可能是数组或者链表)。这意味着QList能够灵活地应对不同场景下的需求,尤其是在元素较小或者大量元素已预先分配空间的情况下,它会尽可能地利用连续内存来加速随机访问。

特点与功能

模板类:QList是一个模板类,可以存储任何QObject派生类或者其他POD类型的数据。动态性:QList的大小可以在运行时动态调整,可以随时添加或移除元素。索引访问:支持通过整数索引访问和修改元素,类似于C++的标准库vector。快速插入删除:在列表的开头和末尾进行插入和删除操作非常高效,而在列表中间进行插入和删除时,效率取决于具体实现(数组还是链表)。迭代器:QList也提供了迭代器来进行元素遍历。内存管理:QList自动管理所存储元素的内存,无需手动分配和释放内存。API:提供了丰富的API,包括但不限于append()、prepend()、insert()、removeAt()、takeAt()、replace()等。

优缺点

优点:

内部优化,适合特定情况下的高效存储和访问。支持快速的头部和尾部插入删除。提供了基于索引的操作,直观易用。自动管理内存,减少了手动内存管理错误的可能性。缺点:

如果QList内部采用链表结构存储,在中间插入或删除元素时,虽然不会像普通数组那样导致大量元素移动,但仍然不如QVector(当元素大小远大于指针大小时)的随机插入删除快。当元素大小较大时,如果QList选择链表存储而非数组,那么连续访问性能会下降。

使用示例(增删改查)

#include

#include

// 创建一个存储整数的QList

QList numbers;

// 增加元素

numbers.append(1);

numbers.append(2);

numbers.append(3);

qDebug() << "After appending: " << numbers; // 输出: [1, 2, 3]

// 修改元素

numbers[1] = 10;

qDebug() << "After modifying: " << numbers; // 输出: [1, 10, 3]

// 查询元素

if (numbers.contains(10)) {

qDebug() << "10 is in the list.";

}

// 删除元素

numbers.removeOne(10); // 删除第一个出现的10

qDebug() << "After removing 10: " << numbers; // 输出: [1, 3]

// 查找并替换元素

int index = numbers.indexOf(3);

if (index != -1) {

numbers.replace(index, 20); // 将索引处的3替换为20

}

qDebug() << "After replacing: " << numbers; // 输出: [1, 20]

// 在特定位置插入元素

numbers.insert(1, 5);

qDebug() << "After inserting at index 1: " << numbers; // 输出: [1, 5, 20]

以上代码片段演示了如何使用QList进行基本的增删改查操作。同时,还可以使用takeAt()方法移除并返回指定索引的元素,以及其他更多的高级功能,如反转列表、合并两个列表等。

QVector 详细介绍

QVector 详细介绍

QVector 是 Qt 框架中的一个模板类,类似于 C++ STL 中的 std::vector,它提供了一个动态可变大小的数组,允许高效地存储和操作相同类型的数据。QVector 主要用于需要随机访问和连续存储空间的场景,它的内部实现是一个可动态扩展的连续内存区域。

优点:

快速随机访问:由于数据存储在连续的内存块中,QVector 支持通过索引直接访问元素,具有与静态数组相似的 O(1) 时间复杂度。内存管理:自动处理内存分配和释放,能够根据需要动态增长或收缩容量。迭代器支持:提供随机访问迭代器,便于遍历和算法操作。内置兼容性:作为 Qt 框架的一部分,与其他 Qt 类型如 QList、QSet 等高度集成,且适合信号/槽机制。

缺点:

插入和删除效率:在中间位置插入或删除元素时,可能导致大量元素移动,因为它是基于连续内存布局的。相比于 QList,QList 使用了链表结构,在中间插入和删除时更为高效。内存碎片:随着频繁的插入和删除操作,可能会导致内存空间碎片化,影响性能。

使用示例及增删改查功能演示:

#include

#include

int main() {

// 创建一个空的 QVector

QVector numbers;

// 添加元素(增):

numbers.append(10);

numbers.append(20);

numbers.append(30);

// 插入元素(增):

numbers.insert(1, 15); // 在索引1处插入15

qDebug() << "After insertion:" << numbers; // 输出:[10, 15, 20, 30]

// 修改元素(改):

numbers[1] = 16;

qDebug() << "After modification:" << numbers; // 输出:[10, 16, 20, 30]

// 查找元素:

if (numbers.contains(16)) {

qDebug() << "16 is in the vector.";

}

// 删除最后一个元素

numbers.pop_back();

// 获取第一个元素

int first = numbers.first();

// 获取最后一个元素

int last = numbers.last();

// 删除元素(删):

numbers.removeAt(1);

qDebug() << "After removal of index 1:" << numbers; // 输出:[10, 20, 30]

// 清除所有元素:

numbers.clear();

qDebug() << "After clear:" << numbers; // 输出:[]

return 0;

}

总结: QVector 非常适用于那些需要高效随机访问、不需要频繁插入删除操作的情况,尤其是当你预见到数据集大小可能变动但总体上保持相对稳定时。如果你的应用场景涉及到大量动态插入和删除操作,尤其是在容器中间位置,那么可能需要考虑使用 QList 或其他更适合的数据结构。

QLinkedList 详细介绍

QLinkedList 详细介绍

QLinkedList 是 Qt 框架中的一个模板类,它实现了双向链表数据结构,类似于 C++ STL 中的 std::list。QLinkedList 适用于频繁执行插入和删除操作,特别是在列表中间位置,而不依赖于高效的随机访问。

优点:

插入和删除效率:在任何位置插入和删除元素的时间复杂度通常为 O(1),这是因为链表结构不需要为了插入或删除元素而移动其他元素。内存分配:每个元素都包含指向前后元素的指针,因此可以在非连续的内存区域存储数据,对于大规模数据操作时内存分配更为灵活。迭代器支持:提供了前向迭代器和双向迭代器,方便在链表中进行遍历。

缺点:

随机访问速度:由于不是连续存储,QLinkedList 不支持通过索引快速访问元素,获取指定位置的元素需要从头或尾部开始遍历,时间复杂度为 O(n)。内存消耗:除了存储数据本身,每个元素还需要额外的空间来存储指向前后节点的指针,这相对于连续存储的数据结构(如 QVector)增加了内存开销。

使用示例及增删改查功能演示:

#include

#include

int main() {

// 创建一个空的 QLinkedList

QLinkedList numbers;

// 添加元素(增):

numbers.append(10);

numbers.append(20);

numbers.append(30);

// 插入元素(增):

numbers.insertBefore(numbers.begin(), 5); // 在开头插入5

qDebug() << "After insertion:" << numbers; // 输出:[5, 10, 20, 30]

// 修改元素(改):

auto it = numbers.begin(); // 获取第一个元素的迭代器

++it; // 移动到第二个元素

*it = 15; // 修改第二个元素的值

qDebug() << "After modification:" << numbers; // 输出:[5, 15, 20, 30]

// 查找并修改元素:

for (auto it = numbers.begin(); it != numbers.end(); ++it) {

if (*it == 20) {

*it = 25;

break;

}

}

qDebug() << "After searching and modifying:" << numbers; // 输出:[5, 15, 25, 30]

// 删除元素(删):

it = numbers.begin(); // 获取第一个元素迭代器

++it; // 移动到要删除的元素

numbers.erase(it); // 删除第二个元素

qDebug() << "After removal:" << numbers; // 输出:[5, 25, 30]

// 清空链表:

numbers.clear();

qDebug() << "After clear:" << numbers; // 输出:[]

return 0;

}

总结: QLinkedList 在插入和删除操作频繁,尤其当列表顺序经常改变的场合表现优秀。如果你的应用程序要求高效地在列表任意位置插入或删除数据,并且不十分依赖于随机访问的速度,QLinkedList 就是一个理想的选择。但对于需要快速随机访问或者对内存占用有严格限制的场景,则应考虑使用 QVector 等连续存储的数据结构。

QStack 详细介绍

QStack 详细介绍

QStack 是 Qt 框架提供的一个模板类,它实现了栈(Stack)这一数据结构,遵循后进先出(Last In, First Out, LIFO)原则。栈在编程中非常常见,主要用于那些需要“最后加入的元素最先取出”的逻辑场景。

优点:

操作简单:QStack 提供了基本的堆栈操作,如 push()(入栈)、pop()(出栈)和 top()(查看栈顶元素),易于理解和使用。高效:由于其简单的数据结构特性,入栈和出栈操作通常具有 O(1) 的时间复杂度。兼容性:作为 Qt 容器类的一部分,QStack 可以很好地与其它 Qt 类型配合使用,并支持 Qt 的信号和槽机制。

缺点:

受限的功能:相较于其他的容器类如 QVector 和 QList,QStack 的功能较为有限,仅针对堆栈特性的操作进行了优化,不适合需要高效随机访问或在容器中部插入和删除元素的场景。无内置查找方法:QStack 并未提供直接查找特定元素的方法,如果需要查找某个元素,需要手动遍历整个栈,这是栈数据结构本身的局限性。

使用示例及增删改查功能演示:

#include

#include

int main() {

// 创建一个空的 QStack

QStack stack;

// 增加元素(入栈)

stack.push(10);

stack.push(20);

stack.push(30);

qDebug() << "After pushing elements:" << stack; // 输出可能是 "[30, 20, 10]",实际输出顺序取决于 Qt 库的实现

// 查看栈顶元素(读取)

int topElement = stack.top();

qDebug() << "Top element is:" << topElement; // 输出:30

// 删除并返回栈顶元素(出栈)

int poppedElement = stack.pop();

qDebug() << "Popped element is:" << poppedElement; // 输出:30

qDebug() << "After popping an element:" << stack; // 输出可能是 "[20, 10]"

// 注意:QStack 不支持在栈中直接修改元素,若需修改栈顶元素,需先 pop 再 push 修改后的值

// 清空栈

stack.clear();

qDebug() << "After clearing the stack:" << stack; // 输出:""

return 0;

}

// 注意:虽然 QStack 继承自 QVector 或 QList 的信息存在一些矛盾,实际上 QStack 的继承关系可能随 Qt 版本不同有所变化,

// 在某些版本中它继承自 QVector,而在另一些版本中可能继承自 QList,但无论如何,它都保留了栈的核心操作。

总结:QStack 主要用于简化堆栈操作,适用于需要快速存取和按先进后出顺序处理数据的场景。不过,由于其设计目的单一,对于需要复杂查询或排序需求的数据处理来说不太适用。另外,关于 QStack 继承自哪个基类,建议查阅最新的 Qt 文档以获得准确信息。

QQueue 详细介绍

QQueue 详细介绍

QQueue 是 Qt 框架中的一个模板类,它实现了队列(Queue)数据结构,遵循先进先出(First In, First Out, FIFO)的原则。队列是一个线性表,新添加的元素会被放在队列的末尾(称为enqueue),而从队列中移除或读取元素则会从队列的前端开始(称为dequeue)。

优点:

队列操作:QQueue 提供了便捷的方法进行队列操作,比如 enqueue()(入队)和 dequeue()(出队)以及 head()(查看队首元素)等。高效性:QQueue 继承自 QList,这意味着它可以充分利用 QList 的内存管理和性能优势,尤其是在队列头部和尾部插入或删除元素时,QList 的内存分配策略保证了较高的效率。兼容性:由于继承自 QList,QQueue 可以使用 QList 的大部分成员函数,例如 size()(获取队列长度)、clear()(清空队列)等,也可以使用迭代器进行遍历。

缺点:

线程安全性:QQueue 自身并非线程安全的,所以在多线程环境下需要开发者自己负责同步,通常可以通过互斥锁(QMutex)或其他并发控制机制来保证线程安全。插入和删除中间元素:尽管继承自 QList,但由于队列操作的性质,不应该在队列中间进行插入和删除操作,否则将失去队列结构的意义,且可能导致较低的性能。

使用示例及增删改查功能演示:

#include

#include

int main() {

// 创建一个空的 QQueue

QQueue numbersQueue;

// 增加元素(入队)

numbersQueue.enqueue(10);

numbersQueue.enqueue(20);

numbersQueue.enqueue(30);

qDebug() << "After enqueueing elements:" << numbersQueue;

// 查看队首元素(读取,但不移除)

int frontElement = numbersQueue.head();

qDebug() << "Front element is:" << frontElement;

// 删除并返回队首元素(出队)

int dequeuedElement = numbersQueue.dequeue();

qDebug() << "Dequeued element is:" << dequeuedElement;

qDebug() << "After dequeueing an element:" << numbersQueue;

// 修改队列中的元素(由于队列只允许在队尾插入,此处假设我们先出队再重新入队修改后的值)

numbersQueue.dequeue();

numbersQueue.enqueue(frontElement + 1); // 修改原队首元素的值

qDebug() << "After modifying an element by re-enqueuing:" << numbersQueue;

// 清空队列

numbersQueue.clear();

qDebug() << "After clearing the queue:" << numbersQueue;

return 0;

}

注意:QQueue 一般不提倡直接修改队列中的元素,因为它设计的目的在于线性、顺序的数据处理。如确实需要修改队列中的某元素,一般需要先出队再入队修改后的值。

总结:QQueue 适用于那些需要按顺序处理任务、消息传递或者其他先进先出逻辑的场景。它在单线程环境中表现良好,但在多线程环境时需要谨慎处理并发访问问题。由于其基于QList的设计,对尾部的增删操作非常高效,而对于非队首元素的操作则应避免。

QMap 详细介绍

QMap 详细介绍

QMap 是 Qt 框架中的一种关联容器模板类,它实现了关联数组或字典的功能,允许通过键(Key)来存储和检索对应的值(Value)。QMap 中的键值对是按照键的升序排列的,这是它与标准库中 std::map 的主要区别之一。

优点:

排序存储:QMap 中的元素是有序的,根据键的自然排序规则(即键类型需要支持比较运算符 <),这使得可以通过键的顺序遍历整个映射。查找性能:QMap 使用了红黑树(Red-Black Tree)数据结构,插入、删除和查找操作平均时间复杂度为 O(log n),其中 n 是映射中的元素数量。内存管理:Qt 内存管理机制确保了在插入、删除过程中对内存的有效利用,减少不必要的内存复制和移动。丰富的接口:QMap 提供了一系列便利的方法,包括但不限于插入、删除、查找、迭代遍历等操作。

缺点:

内存开销:由于红黑树需要额外的指针来维护平衡结构,QMap 相比于基于哈希表实现的 QHash,内存占用可能稍高。键值类型的限制:键类型必须支持比较运算符 <,这在自定义类型作为键时需要用户自行定义。随机插入删除的效率:虽然查找速度快,但如果频繁在中间位置插入或删除元素,由于树结构调整的需要,可能不如无序的哈希表高效。

使用示例及增删改查功能演示:

#include

#include

int main() {

// 创建一个空的 QMap

QMap studentGrades;

// 插入元素(增)

studentGrades.insert("Alice", 85);

studentGrades.insert("Bob", 90);

studentGrades.insert("Charlie", 88);

qDebug() << "After inserting:" << studentGrades; // 输出键值对的集合

// 修改元素(改)

if (studentGrades.contains("Alice")) {

studentGrades["Alice"] = 92; // 直接通过键修改值

}

qDebug() << "After modification:" << studentGrades;

// 查找元素

bool hasGrade = studentGrades.contains("Alice"); // 检查是否存在键

int aliceGrade = studentGrades.value("Alice", -1); // 获取值,如果没有该键则返回默认值

qDebug() << "Does 'Alice' have a grade? " << hasGrade;

qDebug() << "Grade of Alice: " << aliceGrade;

// 删除元素(删)

studentGrades.remove("Bob");

qDebug() << "After removal of 'Bob':" << studentGrades;

// 迭代遍历

foreach (const QString &name, studentGrades.keys()) {

int grade = studentGrades.value(name);

qDebug() << name << "has grade:" << grade;

}

return 0;

}

总结: QMap 是一种适用于有序键值对存储的理想选择,特别是当应用程序需要按键的自然顺序遍历时。然而,如果对查找效率有极高要求且不在乎元素的顺序,或者需要频繁插入和删除元素,QHash 可能是更好的选择。QMap 能够有效处理各种复杂的键值存储需求,并且因其有序性而增强了代码的可读性和易用性。

QHash 详细介绍

QHash 是 Qt 框架中的一个容器类,用于存储键值对。

优点:

快速的键值查找:基于哈希表实现,提供了高效的查找操作。自动内存管理:不需要手动分配和释放内存。简单易用:提供了方便的接口进行插入、查找、删除等操作。

缺点:

不保证元素的顺序:元素的存储顺序是不确定的。

使用示例:

#include

#include

int main() {

// 创建 QHash 对象

QHash hash;

// 插入键值对

hash["name"] = 10;

hash["age"] = 20;

hash["gender"] = 30;

// 查找键对应的值

int value = hash["name"];

qDebug() << "Value for 'name' : " << value;

// 删除键值对

hash.remove("age");

// 修改键对应的值

hash["gender"] = 40;

// 检查键是否存在

if (hash.contains("name")) {

qDebug() << "Key 'name' exists.";

} else {

qDebug() << "Key 'name' does not exist.";

}

return 0;

}

在上述示例中,演示了 QHash 的增删改查功能:

增:使用 hash["key"] = value; 插入键值对。删:使用 hash.remove("key"); 删除键值对。改:直接重新赋值修改键对应的值。查:使用 hash.contains("key"); 检查键是否存在,使用 hash["key"]; 获取键对应的值。

QSet 详细介绍

QSet 是 Qt 框架中的一个集合类,用于存储唯一元素。

优点:

自动去除重复元素,保证元素的唯一性。快速的查找操作。

缺点:

不保证元素的顺序。

使用示例:

#include

#include

int main() {

// 创建 QSet 对象

QSet set;

// 增加元素

set << 1 << 2 << 3 << 4 << 5;

// 检查元素是否存在

if (set.contains(3)) {

qDebug() << "Element 3 exists in the set.";

} else {

qDebug() << "Element 3 does not exist in the set.";

}

// 删除元素

set.remove(2);

// 修改(实际上是添加或删除)元素

set.insert(6);

// 遍历元素

for (int element : set) {

qDebug() << element;

}

return 0;

}

在上述示例中,演示了 QSet 的增删改查功能:

增:使用 << 操作符或 insert() 函数添加元素。删:使用 remove() 函数删除元素。改:通过添加或删除元素来实现修改。查:使用 contains() 函数检查元素是否存在,使用遍历方式查看所有元素。

QStringList 详细介绍

QStringList 是 Qt 框架中的一个字符串列表类,用于存储和操作一系列字符串。

优点:

提供了方便的字符串列表操作接口。自动管理内存。支持各种常见的列表操作。

缺点:

不适合存储大量数据,性能可能会受到影响。

使用示例:

#include

#include

int main() {

QStringList list;

// 增加元素

list << "apple" << "banana" << "orange";

// 查询元素是否存在

if (list.contains("apple")) {

qDebug() << "Element 'apple' exists in the list.";

} else {

qDebug() << "Element 'apple' does not exist in the list.";

}

// 删除元素

list.removeAll("banana");

// 修改元素

list[0] = "new_apple";

// 遍历元素

for (const QString &str : list) {

qDebug() << str;

}

return 0;

}

在上述示例中,演示了 QStringList 的增删改查功能:

增:使用 << 操作符添加元素。删:使用 removeAll() 函数删除元素。改:通过索引访问并修改元素。查:使用 contains() 函数检查元素是否存在,使用遍历方式查看所有元素。

QByteArray 详细介绍

在 Qt 中,QByteArray类被广泛用于处理二进制数据、图像、音频、视频等多媒体数据,也可以用于网络传输和文件操作等场景。其主要特点如下:

高效性:QByteArray的内部实现使用了指针和引用计数技术,可以高效地存储和访问大量数据。功能强大:QByteArray提供了丰富的字节数组操作函数,例如append、insert、replace、remove等,可以灵活地操作字节数组。支持多种编码方式:QByteArray支持多种编码方式,例如 ASCII、UTF-8、UTF-16 等,可以方便地处理不同编码的数据。

下面给出一个简单例子,用于入门QByteArray:

#include

#include

int main() {

// 定义一个空 QByteArray 对象

QByteArray qByteArray("");

// 在尾部添加字符串

qByteArray.append("daniel");

// 返回数据指针

qDebug() << "qByteArray = " << qByteArray.data() << "\n";

// 返回大小,不保护末尾的 '\n'

qDebug() << "The size of qByteArray is " << qByteArray.size() << "\n";

// 查询重复次数

qDebug() << "The number of occurrences of 'a' is " << qByteArray.count('a') << "\n";

// 更改填充值

qByteArray.fill('a');

// 返回数据指针

qDebug() << "qByteArray = " << qByteArray.data() << "\n";

return 0;

}

以上容器类都是模板类,可以根据需要存储任何兼容类型的对象,并且它们在设计上力求简化接口、提高跨平台兼容性和线程安全性。相较于C++标准模板库(STL),Qt的容器类通常被认为更适合于GUI开发环境,尤其是考虑到多线程同步问题时。

好文推荐

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: