STL容器详解
前言
(1)只要是数据就必须要使用容器 ,程序中的数据放在容器中方便增删改查。
(2)Qt库提供了一组通用的基于模板的容器类( containerclasses )。 这些容器类可以用来存储指定类型的项目( items )。
(3)容器也可以嵌套使用 ,例如QMap<QString,QList > ,这里键的类型是QString ,而值的类型是QList ,需要 注意 ,在后面的“> >”符号之间要有一个空格 ,不然编译器会将它当做“>>”操作符对待。
例如 :如果大家需要一个QString类型的可变大小的数组 ,那么可以使用QVector(QString)。 与STL(Standard Template Library,C++的标准模板库)中的容器类相比 ,Qt中的这些容器类更轻量 ,更安全 ,更容易使用。
The Container Classes(容器介绍)(PS:中英版)
(1)Qt provides the following sequential containers: QList, QLinkedList, QVector, QStack, and QQueue. For most applications, QList is the best type to use. Although it is implemented as an array-list, it provides very fast prepends and appends. If you really need a linked-list, use QLinkedList; if you want your items to occupy consecutive memory locations, use QVector. QStack and QQueue are convenience classes that provide LIFO and FIFO semantics.
(1)Qt提供了以下顺序容器:QList、QLinkedList、QVector、QStack和QQueue。对于大多数应用程序,QList是最好的类型。尽管它是作为数组列表实现的,但它提供了非常快的前置和追加操作。如果你真的需要一个链表,使用QLinkedList;如果你想要你的项目占用连续的内存位置,使用QVector。QStack和QQueue是提供LIFO和FIFO语义的方便类。
(2)Qt also provides these associative containers: QMap, QMultiMap, QHash, QMultiHash, and QSet. The “Multi” containers conveniently support multiple values associated with a single key. The “Hash” containers provide faster lookup by using a hash function instead of a binary search on a sorted set.
(2)Qt还提供了这些关联容器:QMap、QMultiMap、QHash、QMultiHash和QSet。“Multi”容器方便地支持与单个键关联的多个值。“哈希”容器通过使用哈希函数而不是对排序集进行二进制搜索来提供更快的查找。
(3)As special cases, the QCache and QContiguousCache classes provide efficient hash-lookup of objects in a limited cache storage.
(3)作为特殊情况,QCache和qcontinuousscache类在有限的缓存存储中提供对象的高效哈希查找。
JAVA风格(容器and遍历器)
容器 | 只读遍历器 | 读写遍历器 |
---|---|---|
QList,QQueue | QListIterator | QMutableListIterator |
QLinkedList | QLinkedListIterator | QMutableLinkedListIterator |
QVector,QStack | QVectorIterator | QMutableVectorIterator |
QSet | QSetIterator | QMutableSetIterator |
QMap<Key, T>,QMultiMap<Key, T> | QMapIterator | QMutableMapIterator |
QHash<Key, T>,QMultiHash<Key, T> | QHashIterator | QMutableHashIterator |
STL风格(容器and遍历器)
容器 | 只读遍历器 | 读写遍历器 |
---|---|---|
QList,QQueue | QList::const_iterator | QList::iterator |
QLinkedList | QLinkedList::const iterator | QLinkedList::iterator |
QVector,QStack | QVector::const iterator | QVector::iterator |
QSet | QSet::const iterator | QSet::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 |
(1)STL风格迭代器兼容Qt和STL的通用算法( generic algorithms ),而且在速度上进行了优化。 对于每一个容器 类 ,都有两个STL风格迭代器类型 :一个提供了只读访问 ,另一个提供了读写访问。 因为只读迭代器比读写迭代 器要快很多 ,所以应尽可能使用只读迭代器。
(2)STL风格迭代器的API模仿了数组的指针 ,例如 ,使用“++”操作符来向后移动迭代器使其指向下一个项目 ;使 用“*”操作符返回迭代器指向的项目等。 需要说明的是 ,不同于Java风格迭代器 ,STL风格迭代器是直接指向项目 的。 其中一个容器的begin()函数返回了一个指向该容器中第一个项目的迭代器 ,end()函数也返回一个迭代器 ,但 是这个迭代器指向该容器的最后一个项目的下一个假想的虚项目 ,end()标志着一个无效的位置 ,当列表为空时 ,begin()函数等价于end()函数。
QList(链表)
QList是一个模板类它提供了一个列表。
QList实际上是一个T类型项目的指针数组,所以它支持基于索引的访问,
而且当项目的数目小于1000时,可以实现在列表中间进行快速的插入操作。
QList提供了很多方便的接口函数 来操作列表中的项目,例如:
(1)插入操作insert();
(2)替换操作replace();
(3)移除操作removeAt();
(4)移动操作move();
(5)交换操作swap();
(6)在表尾添加项目append();
(7)在表头添加项目prepend();
(8)移除第一个项目removeFirst();
(9)移除最后一个项目removeLast();
(10)从列表中移除一项并获取这个项目takeAt(); //获取指定的项
(11)还有相应的takeFirst()和takeLast(); //获取“第一个项”and“获取最后一个项”
(12)获取一个项目的索引indexOf();
(13)判断是否含有相应的项目contains();
(14)获取一个项目出现的次数count();
对于QList可以使用“<<”操作符来向列表中插入项目,例如:“List << 1 << 3 << 5;”
也可以使用“[]”操作符通过索引来访问一个项目,其中项目是从0开始编号的。
不过,对于只读的访问,另一种方法是使用at()函数,它比“[]”操作符要快很多。
参考源码:
#include "qcontainerclasses.h"
#include <QtWidgets/QApplication>
#include <QDebug>
#include <iostream>
#include <QLinkedList>
using namespace std;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QContainerClasses w;
//w.show();
#if 0
QList<int> qList;
for (int i = 0; i < 10; i++)//插入十个数字
{
qList.append(i); //往后追加
}
qList.prepend(100); //往前追加一个数字100
qDebug() << QString::fromLocal8Bit("原始数据:") << qList;
qDebug() << "************************************************************************";
/* 方法1: for循环遍历 */
qDebug() << QString::fromLocal8Bit("方法1:");
for (int i = 0; i < qList.size(); i++)
{
qDebug() << qList.at(i);//用qList.at()获取位置
qDebug() << qList[i];//取qList[]下标获取位置
}
qDebug() << "************************************************************************";
/* 方法2: foreach
按顺序遍历容器中的所有项,可以使用Qt的foreach关键字。
foreach是对c++语言添加的特定于qt的内容,并使用预处理器实现。
*/
qDebug() << QString::fromLocal8Bit("方法2:");
foreach(int itm, qList)
{
qDebug() << itm; // 结果为A,B,C
}
qDebug() << "************************************************************************";
/* 方法3.1: Java风格迭代器 只读迭代器 */
qDebug() << QString::fromLocal8Bit("方法3:");
QListIterator<int> it(qList); //只读迭代器
while (it.hasNext())//判断是否一直有下一个,直到没有结束
{
qDebug() << it.next();
}
qDebug() << "************************************************************************";
/* 方法3.2: Java风格迭代器 读写迭代器 */
qDebug() << QString::fromLocal8Bit("方法4:");
QMutableListIterator<int> mit(qList); //只读迭代器
while (mit.hasNext())//和上面一样
{
if (mit.next() == 8)//判断是否是第8个嘛,修改值为66
mit.setValue(66);
}
qDebug() << "************************************************************************";
/* 方法4.1: STL风格迭代器 只读迭代器 */
qDebug() << QString::fromLocal8Bit("方法5:");
QList<int>::const_iterator itm;//常迭代器
for (itm = qList.begin(); itm != qList.end(); ++itm)
{
qDebug() << (*itm);//指针遍历打印
}
qDebug() << "************************************************************************";
/* 方法4.1: STL风格迭代器 读写迭代器 */
qDebug() << QString::fromLocal8Bit("方法6:");
QList<int>::iterator itm2;//迭代器
for (itm2 = qList.begin(); itm2 != qList.end(); ++itm2)
{
qDebug() << (*itm2);//指针遍历打印
*itm2 = (*itm2) * 6;//取值->*6赋值回去(PS:本轮不会修改,第二遍遍历值将改变)
}
qDebug() << "************************************************************************";
qDebug() << QString::fromLocal8Bit("方法7");
QList<int>::iterator itm3;//迭代器
for (auto itm3 : qList)//
{
qDebug() << itm3;
}
#endif//QList介绍及其操作
#if 0
//QLinkedList:基于迭代器访问的List,方便快速插入、删除
QLinkedList<int> List;
List << 1 << 3 << 5;//可以用此方法赋值进链表中
foreach(int i, List)//foreach是Qt独有的遍历方法
{
qDebug() << i;
}
#endif//QLinkedList介绍及其遍历方法
return a.exec();
}
QVector(可变数组)
详细参考:vector 笔记c++
QMap(键值对)
STL版参考:map映射
QMap类是一个容器类,它提供了一个基于跳跃列表的字典(a skiplistbased dictionary)。
QMap是Qt的通用容器类之一,它存储(键,值)对并提供了与键相关的值的快速查找。
QMap中提供了很多方便的接口函数,
例如:
(1)插入操作insert() ;
(2)获取值value() ;
(3)是否包含一个键contains() ;
(4)删除一个键remove() ;
(5)删除一个键并获取该键对应的值take() ;
(6)清空操作clear() ;
(7)插入一键多值insertMulti()。
可以使用"[]"操作符插入一个键值对或者获取一个键的值,不过当使用该操作符获取一个不存在的键的值时,会默认向map中插入该键,
为了避免这个情况,可以使用value()函数来获取键的值。当使用value()函数时,如果指定的键不存在,那么默认会返回0,可以在使用该函
数时提供参数来更改这个默认返回的值。
QMap默认是一个键对应一个值的,但是也可以使用insertMulti()进行一键多值的插入,对于一键多值的情况,更方便的是使用QMap的
子类QMultiMap。
参考源码:
#include "qcontainerclasses.h"
#include <QtWidgets/QApplication>
#include <QDebug>
#include <iostream>
#include <QLinkedList>
using namespace std;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QContainerClasses w;
//w.show();
#if 0
QMap<QString, int> map;//构造一个QMap
//赋值方法
map["one"] = 1; // 向map中插入("one",1)
map["three"] = 3;// 向map中插入("three",3)
map.insert("seven", 7); // 使用insert()函数进行插入("seven",7)
//获取键的值,使用"[]"操作符时,如果map中没有该键,那么会自动插入key
qDebug() << "========================================================";
int value1 = map["six"];
qDebug() << "value1:" << value1;
qDebug() << "contains 'six ' ?" << map.contains("six");//检查是否包含six这个key,有则为true,无则为false
// 使用value()函数获取键的值,这样当键不存在时不会自动插入
qDebug() << "========================================================";
int value2 = map.value("five");//获取map的值
qDebug() << "value2:" << value2;//value2默认返回0
qDebug() << "contains 'five ' ?" << map.contains("five");//返回为false
// 当键不存在时,value()默认返回0。当设定了键值后不论有没有这个"key()"或者"value()"会自动插入key
qDebug() << "========================================================";
int value3 = map.value("nine", 9);//没有则插入一个键值
qDebug() << "value3:" << value3;//value3默认返回9
#endif //map赋值操作
#if 0
QMap<int, QString> Employees;//构建一个QMap
//插入数据
Employees.insert(1, "Bob");
Employees.insert(2, "Chad");
Employees.insert(3, "Mary");
Employees.insert(4, "oldWang");
Employees[5] = "Danny"; //不推荐这样赋值,很难分清是下标位置还是key
QMap<int, QString>::const_iterator i = Employees.constBegin();//构造一个const_iterator常迭代器
while (i != Employees.constEnd()) //循环遍历
{
cout << i.key() << ": " << i.value().toStdString() << endl;
++i;
}
cout << "==============================================================="<< endl;
QMap<int, QString>::iterator j = Employees.begin();//构造一个iterator迭代器
for (j; j != Employees.end(); j++)//循环遍历
{
//搜索帮助文档:T &iterator::value() const
/*
例子:
if (i.key() == "Hello")
i.value() = "Bonjour";
*/
if (j.value()=="oldWang")
{
j.value() = "robort";//修改value
}
cout << j.key() << ":" << j.value().toStdString()<<endl;//打印
}
#endif //QMap遍历修改value操作
return a.exec();
}
QHash(哈希算法)
什么是哈希算法参考:什么是哈希(hash)
QMap与QHash的差别 :
(1)QHash具有比QMap更快的查找速度
(2)QHash以任意的顺序存储数据项 ,而QMap总是按照键Key顺序存储数据
(3)QHash的键类型Key必须提供operator==()和一个全局的qHash(Key)函数 ,而QMap的键类型Key必须提供 operator<()函数。
参考源码:
#include "qcontainerclasses.h"
#include <QtWidgets/QApplication>
#include <QDebug>
#include <iostream>
#include <QLinkedList>
using namespace std;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QContainerClasses w;
//w.show();
#if 0
QHash<int, QString> Employees;//构造一个哈希键值,是随机存储的。
//插入键值
Employees.insert(1, "Bob");
Employees.insert(2, "Chad");
Employees.insert(3, "Mary");
//遍历Hash的key
foreach(int i, Employees.keys())
{
qDebug() << Employees[i];//遍历输出值,是随机出现的。
}
QHashIterator<int, QString>Iter(Employees);//构造一个Hash迭代器继承Employees哈希键值
while (Iter.hasNext())//判断是否还有Employees数据
{
Iter.next();//输出下一个数据(PS:必须要有这个,不然会触发中断)
qDebug() << Iter.key() << " = " << Iter.value();//打印数据
}
#endif //哈希算法
return a.exec();
}
常用算法(以下内容均为源码,无介绍)
qsort(排序)
#include "qcontainerclasses.h"
#include <QtWidgets/QApplication>
#include <QDebug>
#include <iostream>
#include <QLinkedList>
using namespace std;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QContainerClasses w;
//w.show();
#if 1
QList<int> list;
list << 36 << 16 << 66 << 6 << 56;
qSort(list.begin(), list.end());//正序排序
qDebug() << QString::fromLocal8Bit("正序排序:") << endl << list;
qSort(list.end(), list.begin(),qGreater<int>());//倒序排序
qDebug() << QString::fromLocal8Bit("倒序排序:") << endl << list;
#endif //qSort(快速排序)
return a.exec();
}
qcopy(复制)
#include "qcontainerclasses.h"
#include <QtWidgets/QApplication>
#include <QDebug>
#include <iostream>
#include <QLinkedList>
using namespace std;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QContainerClasses w;
//w.show();
#if 0
/*****************************************************************/
//基本操作
QStringList list;//构造一个QString链表
list << "a" << "b" << "c";//赋值到list中
QVector<QString> vect(3);//构造一个QVector
//OutputIterator qCopy(InputIterator begin, InputIterator end, OutputIterator dest)
qCopy(list.begin(), list.end(), vect.begin());//将list链表中的数据qCopy到vect中;
foreach(QString item, vect)//遍历QVector
{
qDebug() << item;
}
/*****************************************************************/
cout << "=====================分界线1======================" << endl;
//扩展内容:
QStringList list2;//构造一个QStringList
list2 << "one" << "two" << "three";//赋值三个值到list
QVector<QString> vect1(3);//构造一个QVector
qCopy(list2.begin(), list2.end(), vect1.begin());//将list2链表中的数据qCopy到vect1中;
QVector<QString>::iterator j;//创建一个迭代器
for (auto j : vect1)//遍历vect1
{
qDebug() << j;//打印数据
}
cout << "=====================分界线2======================" << endl;
QVector<QString> vect2(8);//构造一个QVector,给定8个数组大小
//"vect2.begin() + 2"是指距离隔两个数组大小进行qCopy
qCopy(list2.begin(), list2.end(), vect2.begin() + 2);//将list2链表中的数据qCopy到vect2中
QVector<QString>::iterator i;//创建一个迭代器
for (auto i : vect2)//遍历vect2
{
qDebug() << i;//打印数据
}
#endif//qCopy(复制)
return a.exec();
}
qFill(用特定的值填充容器)
#include "qcontainerclasses.h"
#include <QtWidgets/QApplication>
#include <QDebug>
#include <iostream>
#include <QLinkedList>
using namespace std;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QContainerClasses w;
//w.show();
#if 0
QVector<QString> vect(5);//构造一个QVector,5个数组大小
//void qFill(ForwardIterator first, ForwardIterator last, const T &val)
//从下标位置1到end()前两个结束,将"PUBG"赋值进去
qFill(vect.begin() + 1, vect.end()-2, "PUBG");
foreach(QString item, vect)//遍历vect
{
qDebug() << item;//打印数据
}
#endif//qFill()用特定的值填充容器
return a.exec();
}
qfind(查找)
#include "qcontainerclasses.h"
#include <QtWidgets/QApplication>
#include <QDebug>
#include <iostream>
#include <QLinkedList>
using namespace std;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QContainerClasses w;
//w.show();
#if 0
/*******************************************************************************/
//Qlist使用qfind
QList<int> List;//构造一个QList
List << 1 << 5 << 15 << 25;//赋值到List中
//InputIterator qFind(InputIterator first, InputIterator last, const T &val)
//InputIterator qFind(从List开头,到List结尾,查找值)
QList<int>::const_iterator Iter = qFind(List.begin(), List.end(), 25);
if (Iter != List.end())//判断是否查询到了结尾处
{
qDebug() << "Find: " << *Iter;//打印查找到的数据
}
else
{
qDebug() << "Not Find";//查找失败
}
/*******************************************************************************/
cout << "=====================分界线1======================" << endl;
//QMap使用qfind
QMap<QString, QString> Employees;//构造一个QMap,(会自动对key进行排序)
//给QMap赋键值
Employees.insert("c++", "Bob");
Employees.insert("win32", "xiaqi");
Employees.insert("mfc", "laowang");
Employees.insert("qt", "mengfan");
Employees["linux"] = "Danny";
/* Danny 变laowang */
//用iterator查找key: find("linux");
QMap<QString, QString>::iterator i = Employees.find("linux");
while (i != Employees.end() && i.key() == "linux")//判断是否查找到结尾并且key值为"linux";
{
qDebug() << i.key() << i.value();//打印原数据
i.value() = "oldwang";//更换value值
++i;
}
cout << "=====================分界线2======================" << endl;
/* 再遍历一次 */
i = Employees.begin();//重新给iterator赋值到开头位置
while (i != Employees.end())//判断是否为结尾处
{
qDebug() << i.key() << i.value();//打印更新后数据
++i;
}
#endif
return a.exec();
}