QT--容器

发布于:2025-02-11 ⋅ 阅读:(55) ⋅ 点赞:(0)

在 Qt 中,容器类是用于存储和管理数据的核心工具。Qt 提供了一系列高效的容器类,这些容器类设计用于 C++ 编程,并且与 Qt 的信号与槽机制、隐式共享(Implicit Sharing)等特性紧密集成。Qt 的容器类比标准库的 std::vectorstd::list 等容器更加轻量级,并且在某些情况下性能更好。


1. Qt 容器的特点

  • 隐式共享:Qt 容器是隐式共享的,这意味着在复制容器时,只有当修改数据时才会真正复制,从而提高了性能。
  • 线程安全:Qt 容器在单线程环境下是线程安全的,但在多线程环境下需要手动同步。
  • 与 STL 兼容:Qt 容器提供了与标准库容器的兼容接口,可以与 STL 算法一起使用。
  • 轻量级:Qt 容器的内存占用通常比标准库容器更小。

2. Qt 容器类概览

Qt 提供了多种容器类,适用于不同的场景:

容器类 描述 适用场景
QList<T> 动态数组,支持快速随机访问和快速插入/删除。 常用容器,适合大多数场景。
QLinkedList<T> 双向链表,支持快速插入/删除,但不支持随机访问。 需要频繁插入/删除操作的场景。
QVector<T> 动态数组,支持快速随机访问和快速尾部插入。 需要高效随机访问的场景。
QSet<T> 集合,存储唯一元素,支持快速查找。 需要存储唯一元素的场景。
QMap<Key, T> 有序映射,按键排序存储键值对。 需要按键排序的场景。
QMultiMap<Key, T> 多值映射,支持一个键对应多个值。 需要一个键对应多个值的场景。
QHash<Key, T> 无序映射,支持快速查找。 需要快速查找的场景。
QMultiHash<Key, T> 多值哈希,支持一个键对应多个值。 需要一个键对应多个值的场景。
QStack<T> 栈,后进先出(LIFO)。 需要栈结构的场景。
QQueue<T> 队列,先进先出(FIFO)。 需要队列结构的场景。

3. 常用容器详解

3.1 QList<T>

QList 是 Qt 中最常用的容器类,类似于 std::vector,但具有更高的性能。

#include <QList>
#include <QDebug>

int main() {
    QList<int> list;
    list << 1 << 2 << 3;  // 添加元素

    qDebug() << "List:" << list;  // 输出: List: (1, 2, 3)

    list.append(4);  // 追加元素
    list.prepend(0);  // 在头部插入元素

    qDebug() << "List after modification:" << list;  // 输出: List: (0, 1, 2, 3, 4)

    return 0;
}

3.2 QLinkedList<T>

QLinkedList 是双向链表,适合频繁插入和删除操作。

#include <QLinkedList>
#include <QDebug>

int main() {
    QLinkedList<int> list;
    list << 1 << 2 << 3;

    qDebug() << "LinkedList:" << list;  // 输出: LinkedList: (1, 2, 3)

    list.append(4);
    list.prepend(0);

    qDebug() << "LinkedList after modification:" << list;  // 输出: LinkedList: (0, 1, 2, 3, 4)

    return 0;
}

3.3 QVector<T>

QVector 类似于 QList,但更适合需要高效随机访问的场景。

#include <QVector>
#include <QDebug>

int main() {
    QVector<int> vector;
    vector << 1 << 2 << 3;

    qDebug() << "Vector:" << vector;  // 输出: Vector: (1, 2, 3)

    vector.append(4);
    vector.prepend(0);

    qDebug() << "Vector after modification:" << vector;  // 输出: Vector: (0, 1, 2, 3, 4)

    return 0;
}

3.4 QSet<T>

QSet 是集合,存储唯一元素,支持快速查找。

#include <QSet>
#include <QDebug>

int main() {
    QSet<int> set;
    set << 1 << 2 << 3 << 2 << 1;  // 重复元素会被忽略

    qDebug() << "Set:" << set;  // 输出: Set: {1, 2, 3}

    set.insert(4);

    qDebug() << "Set after modification:" << set;  // 输出: Set: {1, 2, 3, 4}

    return 0;
}

3.5 QMap<Key, T>

QMap 是有序映射,按键排序存储键值对。

#include <QMap>
#include <QDebug>

int main() {
    QMap<QString, int> map;
    map.insert("Alice", 25);
    map.insert("Bob", 30);
    map.insert("Charlie", 35);

    qDebug() << "Map:" << map;  // 输出: Map: {("Alice", 25), ("Bob", 30), ("Charlie", 35)}

    map.insert("David", 40);

    qDebug() << "Map after modification:" << map;  // 输出: Map: {("Alice", 25), ("Bob", 30), ("Charlie", 35), ("David", 40)}

    return 0;
}

3.6 QHash<Key, T>

QHash 是无序映射,支持快速查找。

#include <QHash>
#include <QDebug>

int main() {
    QHash<QString, int> hash;
    hash.insert("Alice", 25);
    hash.insert("Bob", 30);
    hash.insert("Charlie", 35);

    qDebug() << "Hash:" << hash;  // 输出: Hash: {("Charlie", 35), ("Bob", 30), ("Alice", 25)}

    hash.insert("David", 40);

    qDebug() << "Hash after modification:" << hash;  // 输出: Hash: {("Charlie", 35), ("Bob", 30), ("Alice", 25), ("David", 40)}

    return 0;
}

3.7 QStack<T>

QStack 是栈,后进先出(LIFO)。

#include <QStack>
#include <QDebug>

int main() {
    QStack<int> stack;
    stack.push(1);
    stack.push(2);
    stack.push(3);

    qDebug() << "Stack:" << stack;  // 输出: Stack: QStack(3, 2, 1)

    int top = stack.pop();  // 弹出栈顶元素
    qDebug() << "Popped element:" << top;  // 输出: Popped element: 3

    return 0;
}

 

3.8 QQueue<T>

QQueue 是队列,先进先出(FIFO)。

#include <QQueue>
#include <QDebug>

int main() {
    QQueue<int> queue;
    queue.enqueue(1);
    queue.enqueue(2);
    queue.enqueue(3);

    qDebug() << "Queue:" << queue;  // 输出: Queue: QQueue(1, 2, 3)

    int front = queue.dequeue();  // 移除队列头部元素
    qDebug() << "Dequeued element:" << front;  // 输出: Dequeued element: 1

    return 0;
}

4. Qt 容器的迭代器

Qt 容器提供了多种迭代器,用于遍历容器中的元素。迭代器分为两种类型:

  • 只读迭代器:用于遍历容器中的元素,但不能修改元素。
  • 读写迭代器:用于遍历和修改容器中的元素。

4.1 只读迭代器

#include <QList>
#include <QDebug>

int main() {
    QList<int> list = {1, 2, 3, 4, 5};

    // 使用只读迭代器遍历
    QList<int>::const_iterator it;
    for (it = list.constBegin(); it != list.constEnd(); ++it) {
        qDebug() << *it;  // 输出: 1 2 3 4 5
    }

    return 0;
}

4.2 读写迭代器

#include <QList>
#include <QDebug>

int main() {
    QList<int> list = {1, 2, 3, 4, 5};

    // 使用读写迭代器遍历并修改元素
    QList<int>::iterator it;
    for (it = list.begin(); it != list.end(); ++it) {
        *it *= 2;  // 将每个元素乘以 2
    }

    qDebug() << "Modified list:" << list;  // 输出: Modified list: (2, 4, 6, 8, 10)

    return 0;
}

5. Qt 容器的隐式共享

Qt 容器是隐式共享的,这意味着在复制容器时,只有当修改数据时才会真正复制,从而提高了性能。

示例:隐式共享

#include <QList>
#include <QDebug>

int main() {
    QList<int> list1 = {1, 2, 3};
    QList<int> list2 = list1;  // 浅拷贝,共享数据

    qDebug() << "list1:" << list1;  // 输出: list1: (1, 2, 3)
    qDebug() << "list2:" << list2;  // 输出: list2: (1, 2, 3)

    list2[0] = 10;  // 修改 list2,触发深拷贝

    qDebug() << "After modification:";
    qDebug() << "list1:" << list1;  // 输出: list1: (1, 2, 3)
    qDebug() << "list2:" << list2;  // 输出: list2: (10, 2, 3)

    return 0;
}

6. Qt 容器与 STL 的兼容性

Qt 容器提供了与标准库容器的兼容接口,可以与 STL 算法一起使用。

示例:使用 STL 算法

#include <QList>
#include <QDebug>
#include <algorithm>  // 包含 STL 算法

int main() {
    QList<int> list = {3, 1, 4, 1, 5, 9};

    // 使用 STL 的 sort 算法
    std::sort(list.begin(), list.end());

    qDebug() << "Sorted list:" << list;  // 输出: Sorted list: (1, 1, 3, 4, 5, 9)

    return 0;
}

7. Qt 容器的性能对比

容器类 随机访问 插入/删除 内存占用 适用场景
QList<T> 中等 常用容器,适合大多数场景。
QLinkedList<T> 需要频繁插入/删除操作的场景。
QVector<T> 需要高效随机访问的场景。
QSet<T> 需要存储唯一元素的场景。
QMap<Key, T> 需要按键排序的场景。
QHash<Key, T> 需要快速查找的场景。

8. 总结

Qt 提供了丰富的容器类,适用于不同的场景。以下是一些建议:

  • 常用容器QList 是最常用的容器,适合大多数场景。
  • 高效随机访问QVector 是更好的选择。
  • 频繁插入/删除QLinkedList 是更好的选择。
  • 唯一元素QSet 是更好的选择。
  • 键值对存储QMap 和 QHash 分别适用于有序和无序的场景。

通过合理选择和使用 Qt 容器,可以提高代码的性能和可读性。

 


网站公告

今日签到

点亮在社区的每一天
去签到