QT: работаем с библиотекой контейнеров Tulip
Библиотека Tulip – встроенный в QT (модуль QtCore) аналог STL (Standard Template Library, стандартная библиотека шаблонов языка C++).
В основе библиотеки лежат 3 понятия:
- контейнеры - классы, способные хранить в себе элементы различных типов данных;
- алгоритмы – операции преобразования над элементами контейнеров, такие, как сортировка, поиск, сравнение и т.п.;
- итераторы - связывают контейнеры и алгоритмы, позволяют перемещаться по элементами контейнера, абстрагируясь от конкретной структуры данных.
Работать с этими возможностями очень легко, в заметке мы рассмотрим несколько типовых примеров.
1. Контейнерные классы (контейнеры):
Последовательные (упорядоченные коллекции, в которых каждый элемент занимает определенную позицию):
QVector<T> — вектор;
QList<T> — список;
QLinkedList<T> — двусвязный список;
QStack<T> — стек;
QQueue<T> — очередь.
Ассоциативные (коллекции, в которых позиция элемента зависит от его значения):
QSet<T> — множество;
QMap<K,T> — словарь, хранящий соответствия ключей типа K и значений типа T (значения хранятся упорядоченными по ключу);
QMultiMap<K,T> — мультисловарь, может связывать с одним ключом множество значений;
QHash<K,T> — хэш, набор пар "ключ-значение", данные хранятся в произвольном порядке;
QMultiHash<K,T> — мультихэш, может связывать с одним ключом хэша множество значений.
Здесь
- <T> - обозначение типа данных (например, QString, int)
- <K> - тип данных ключа, по которому упорядочиваются данные (только для указанных типов контейнеров).
Общие операторы и методы всех контейнеров |
|
Оператор, метод |
Описание |
== и != |
Операторы сравнения, равно и не равно |
= |
Оператор присваивания |
[] |
Оператор индексации. Исключение составляют только классы QSet<T> и QLinkedList<T>, в них этот оператор не определен |
begin() и constBegin() |
Методы, возвращающие итераторы, установленные на начало последовательности элементов контейнера. Для класса QSet<T> возвращаются только константные итераторы |
end() и constEnd() |
Методы, возвращающие константные итераторы, установленные на конец последовательности элементов контейнера |
clear() |
Удаление всех элементов контейнера |
insert() |
Операция вставки элементов в контейнер |
remove() |
Операция удаления элементов из контейнера |
size() и count() |
Оба метода идентичны — возвращают количество элементов контейнера, но применение первого предпочтительно, т. к. соответствует STL |
value() |
Возвращает значение элемента контейнера. В QSet<T> этот метод не определен |
empty() и isEmpty() |
Возвращают true, если контейнер не содержит ни одного элемента. Оба метода идентичны, но применение первого предпочтительно, т. к. соответствует STL |
Общие методы последовательных контейнеров |
|
Оператор/метод |
Описание |
+ |
Объединяет элементы двух контейнеров |
+= |
Добавляет элемент в контейнер (то же, что и <<) |
<< |
Добавляет элемент в контейнер |
at() |
Возвращает указанный элемент |
back() и last() |
Возвращают ссылку на последний элемент. Эти методы предпо-лагают, что контейнер не пуст. Оба метода back() и last() идентичны, но применение первого предпочтительнее, т. к. он соответствует STL |
contains() |
Проверяет, содержится ли переданный в качестве параметра элемент в контейнере |
erase() |
Удаляет элемент, расположенный на позиции итератора, передаваемого в качестве параметра |
front() и first() |
Возвращают ссылку на первый элемент контейнера. Методы предполагают, что контейнер не пуст. Оба метода front() и first() идентичны, но применение первого более предпочтительно, т. к. он соответствует STL |
indexOf() |
Возвращает позицию первого совпадения найденного в контейнере элемента, в соответствии с переданным в метод значением. Внимание: в контейнере QLinkedList этот метод отсутствует |
lastIndexOf() |
Возвращает позицию последнего совпадения найденного в контейнере элемента, в соответствии с переданным в метод значением. Внимание: в контейнере QLinkedList этот метод отсутствует |
mid() |
Возвращает контейнер, содержащий копии элементов, задаваемых начальной позицией и количеством |
pop_back() |
Удаляет последний элемент контейнера |
pop_front() |
Удаляет первый элемент контейнера |
push_back() и append() |
Методы добавляют один элемент в конец контейнера. Оба метода идентичны, но применение первого предпочтительно, т. к. он соответствует STL |
push_front() и prepend() |
Методы добавляют один элемент в начало контейнера. Оба ме-тода идентичны, но применение первого предпочтительно, т. к. он соответствует STL |
replace() |
Заменяет элемент, находящийся на заданной позиции, значением, переданным как второй параметр |
Некоторые методы контейнера QVector<T> |
|
Метод |
Описание |
data() |
Возвращает указатель на данные вектора (т. е. на обычный массив) |
fill() |
Присваивает одно и то же значение всем элементам вектора |
reserve() |
Резервирует память для количества элементов, в соответствии с переданным значением |
resize() |
Устанавливает размер вектора в соответствии с переданным значением |
toList() |
Возвращает объект QList с элементами, содержащимися в векторе |
toStdVector() |
Возвращает объект std::vector с элементами, содержащимися в векторе |
Пример 1. Добавление строк и целых чисел в вектор
QVector <QString> vs;
vs.append("Item1");
vs += "Item2";
qDebug() << vs;
QVector <int> vi;
vi.push_back(1);
vi += 2;
qDebug() << vi;
Замечание. Здесь и далее предполагается, что в проект включены соответствующие заголовки QT, например, для показанного выше кода требуется
#include <QVector>
#include <QDebug>
Некоторые методы контейнера QList<T> |
|
Метод |
Описание |
move() |
Перемещает элемент с одной позиции на другую |
removeFirst() |
Удаляет первый элемент списка |
removeLast() |
Удаляет последний элемент списка |
swap() |
Меняет местами два элемента на указанных позициях |
takeAt() |
Возвращает элемент на указанной позиции и удаляет его |
takeFirst() |
Удаляет первый элемент и возвращает его |
takeLast() |
Удаляет последний элемент и возвращает его |
toSet() |
Возвращает контейнер QSet<T> с данными, содержащимися в объекте QList<T> |
toStdList() |
Возвращает стандартный список STL std::list<T> с элементами, содержащимися в объекте QList<T> |
toVector() |
Возвращает объект вектора QVector<T> с элементами, содержащимися |
Пример 2. Формирование списка строк и обмен местами первого элемента с последним.
QList <QString> list;
cout << "Enter the strings, 0 is the end of input" << endl;
QTextStream qtcin(stdin);
QString s;
for (;;) {
s = qtcin.readLine();
//qtcin >> s; //если чтение до пробела
if (s.compare("0")==0) break;
list << s;
}
list.swap(0,list.size()-1);
qDebug() << list;
Общие методы ассоциативных контейнеров |
|
Метод |
Описание |
contains() |
Возвращает значение true, если контейнер содержит элемент с заданным ключом. Иначе возвращается значение false |
erase() |
Удаляет элемент из контейнера в соответствии с переданным итератором |
find() |
Осуществляет поиск элемента по значению. В случае успеха возвращает итератор, указывающий на этот элемент, а в случае неудачи итератор указывает на метод end() |
insertMulti() |
Вставляет в контейнер новый элемент. Если элемент уже присутствует в контейнере, то создается новый элемент. Данный метод отсутствует в классе QSet<T> |
insert() |
Вставляет в контейнер новый элемент. Если элемент уже присутствует в контейнере, он замещается новым элементом. Данный метод отсутствует в классе QSet<T> |
key() |
Возвращает первый ключ в соответствии с переданным в этот метод значением. Данный метод отсутствует в классе QSet<T> |
keys() |
Возвращает список всех ключей, находящихся в контейнере. Данный метод отсутствует в классе QSet<T> |
take() |
Удаляет элемент из контейнера в соответствии с переданным ключом и возвращает копию его значения. Данный метод отсутствует в классе QSet<T> |
unite() |
Добавляет элементы одного контейнера в другой |
values() |
Возвращает список всех значений, находящихся в контейнере |
Пример 3. Заполнение простого телефонного справочника
QMap <QString, QString> phoneBook;
phoneBook["Masha"] = "+79131234567";
phoneBook["Vasya"] = "+79537654321";
QMap <QString, QString>::iterator it = phoneBook.begin();
for (;it!= phoneBook.end(); ++it) qDebug() << "Name=" << it.key()
<< " Phone=" << it.value();
Некоторые методы контейнера QSet <T> |
|
Метод |
Описание |
intersect() |
Удаляет элементы множества, не присутствующие в переданном множестве (пересечение множеств) |
reserve() |
Задает размер хэш-таблицы множества |
squeeze() |
Уменьшает объем внутренней хэш-таблицы для экономии памяти |
subtract() |
Удаляет элементы множества, присутствующие в переданном множестве (разность множеств) |
toList() |
Возвращает объект типа QList<T>, содержащий элементы множества QSet<T> |
unite() |
Объединяет элементы двух множеств |
Пример 4. Объединение, пересечение и разность 2 числовых множеств
QSet <int> set1;
QSet <int> set2;
set1 << 1 << 2 << 3;
set2 << 2 << 3 << 4;
QSet <int> setUnion = set1;
setUnion.unite (set2);
qDebug() << "Union = " << setUnion.toList();
QSet <int> setIntersect = set1;
setIntersect.intersect(set2);
qDebug() << "Intersection = " << setIntersect.toList();
QSet <int> setSubtract = set1;
setSubtract.subtract(set2);
qDebug() << "Subtraction = " << setSubtract.toList();
2. Итераторы позволяют перемещаться по элементам контейнера, абстрагируясь от структуры данных.
Методы QListIterator, QLinkedListIterator, QVectorIterator, QHashIterator, QMapIterator , QSetIterator |
|
Метод |
Описание |
toFront() |
Перемещает итератор на начало списка |
toBack() |
Перемещает итератор на конец списка |
hasNext() |
Возвращает значение true, если итератор не находится в конце списка |
next() |
Возвращает значение следующего элемента списка и перемещает итератор на следующую позицию |
peekNext() |
Просто возвращает следующее значение без изменения позиции итератора |
hasPrevious() |
Возвращает значение true, если итератор не находится в начале списка |
previous() |
Возвращает значение предыдущего элемента списка и перемещает итератор на предыдущую позицию |
peekPrevious() |
Возвращает предыдущее значение без изменения позиции итератора |
findNext(const T&) |
Поиск заданного элемента в прямом направлении |
findPrevious(const& T) |
Поиск заданного элемента в обратном направлении |
Пример 5. Сканирование списка строк с помощью итератора
QList <QString> list;
list << " Item1 " << " Item2 " << " Item3 ";
QListIterator <QString> it(list);
while(it.hasNext()) {
ui->textEdit->setText(ui->textEdit->toPlainText()+"\n"+it.next());
}
Если необходимо производить изменения в процессе прохождения итератором элементов, то для этого следует воспользоваться изменяющимися (mutable) итераторами. Их классы называются аналогично, но с добавлением "Mutable": QMutableListIterator, QMutableHashIterator, QMutableLinkedListIterator, QMutableMapIterator и QmutableVector-Iterator. Метод remove() удаляет текущий элемент, а insert() производит вставку элемента в текущую позицию. При помощи метода setValue() можно присвоить элементу другое значение.
Пример 6. Замена значения элемента в списке
QList <QString> list;
list << "Item1" << "Item2" << "Item3";
QMutableListIterator <QString> it(list);
while (it.hasNext()) if (it.next()=="Item3") it.setValue("3Item");
qDebug() << list;
В QT также работают итераторы в стиле STL:
QVector <QString> vec;
vec << "Item1" << "Item2" << "Item3";
Пример 7. Прямой проход по вектору строк.
QVector<QString>::iterator it = vec.begin();
for (; it != vec.end(); ++it) {
qDebug() << "Element:" << *it;
}
Пример 8. Обратный проход по вектору строк.
QVector<QString>::iterator it = vec.end();
for (;it != vec.begin();) {
--it;
qDebug() << "Element:" << *it;
}
3. Алгоритмы определены в заголовочном файле QtAlgorithms и представляют собой операции, применяемые к контейнерам, такие как сортировка, поиск, преобразование данных и т.д. Следует отметить, что алгоритмы реализованы не в виде методов контейнерных классов, а в виде шаблонных функций, что позволяет использовать их как для любого контейнерного класса Tulip, так и для обычных массивов. Например, для копирования элементов из одного массива в другой можно задействовать алгоритм qCopy().
Пример 9. Копирование массива строк с помощью алгоритма
QString values[] = {"Xandria", "Therion", "Nightwish", "Haggard"};
const int n = sizeof(values) / sizeof(QString);
QString copyOfValues[n];
qCopy (values, values + n, copyOfValues);
Алгоритмы |
|
Алгоритм |
Описание |
qBinaryFind() |
Двоичный поиск заданных значений |
qCopy() |
Копирование элементов, начиная с первого |
qCopyBackward() |
Копирование элементов, начиная с последнего |
qCount() |
Подсчет элементов контейнера |
qDeleteAll() |
Удаление всех элементов. Необходимо, чтобы элементы контейнера не были константными указателями |
qEqual() |
Сравнение. Необходимо, чтобы для размещенных объектов был определен оператор == |
qFill() |
Присваивает всем элементам контейнера заданное значение |
qFind() |
Поиск заданных значений |
qLowerBound() |
Нахождение первого элемента со значением, большим либо равным заданного |
qUpperBound() |
Нахождение первого элемента со значением, строго большим заданного |
qSort() |
Сортировка элементов |
qStableSort() |
Сортировка элементов с сохранением порядка следования равных элементов |
qSwap() |
Перемена двух значений местами |
Пример 10. Сортировка списка строк с помощью алгоритма
QList<QString> list;
list << "gamma" << "beta" << "alpha";
qSort(list);
qDebug() << "Sorted list=" << list;
Пример 11. Поиск в списке строк значения с помощью алгоритма
QList<QString> list;
list << "alpha" << "beta" << "gamma";
QList<QString>::iterator it =
qFind(list.begin(), list.end(), "gamma");
if (it != list.end()) {
qDebug() << "Found=" << *it;
}
else {
qDebug() << "Not Found";
}
Если найденных строк может быть несколько, возможна организация типового цикла поиска значений:
QList<QString> list;
list << "gamma" << "alpha" << "beta" << "gamma";
bool found = false;
QList<QString>::iterator it = list.begin();
do {
it = qFind(it, list.end(), "gamma");
if (it != list.end()) {
qDebug() << "Found=" << *it << " at " << (it.i-list.begin().i);
found = true;
++it;
}
} while (it != list.end());
if (!fЗадача 1. Найти количество вхождений минимального элемента в целочисленный список.
#include <QCoreApplication>#include <QVector>#include <QtAlgorithms>#include <QDebug>#include <iostream>using namespace std;int cnt_min (QVector <int> list) {qSort(list);int cnt = 0, min = list.at(0);QVectorIterator <int> it(list);while(it.hasNext() && it.peekNext()==min) { cnt++; it.next(); }return cnt;}int main() {QVector <int> list;list << -5 << 5 << -1 << -5 << 3 << 3 << -5;qDebug() << cnt_min(list);return 0;}Задача 2. Удалить из очереди строк элементы короче 4 символов.
#include <QCoreApplication>#include <QQueue>#include <QtAlgorithms>#include <QDebug>#include <iostream>using namespace std;QQueue <QString> delete_ (QQueue <QString> q,int len) {QQueue <QString> q2;while (!q.isEmpty()) {QString qs=q.dequeue();if (qs.size()>=len) q2.enqueue(qs);}return q2;}int main() {QQueue <QString> queue;queue << "It's" << "my" << "life" << "la-la" << "," << "hello";QQueue <QString> queue2 = delete_(queue,4);qDebug() << queue2;return 0;}Статья не исчерпывает всех возможностей Tulip, например, в этой заметке есть пример на удобный список строк
QStringList
, являющийся потомкомQList
.
16.03.2016, 23:30; рейтинг: 9302