QList 和std::list的比较

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QList 和std::list的比较相关的知识,希望对你有一定的参考价值。

QList

QList<T> 是一个Qt通用容器类。它存储一序列的值,并且提供基于索引的数据访问方法和快速的插入和删除操作。

QList<T>, QLinkedList<T>, 和 QVector<T>提供类似的功能,这里进行几点概述:

1.     大多数情况下,最好使用QList。它基于索引的API比QLinkedList基于迭代器的API方便。它存储数据的方式也使得它比QVector存取数据的数度快。而且它在可执行文件中扩展的代码也比较少。

2.    需要一个真正的链表,能保证在中间插入数据的时间复杂度是常量的,用迭代器来存钱元素的,那可以用QLinkedList

3.     如果想容器的元素在相邻的内存,可以用QVector。

在内部,QList<T>是一个指向T类型的指针数组。如果T本身是一个指针类型或者不大于指针的基本数据类型,或者如果T是一个Qt共享类,QList<T>在直接将元素保持在指针数组中。对于少于一千个元素的链表,这样的数组表示允许在中间快速的插入,而且运行基于索引的存钱方法。此外,prepend() and append() 操作速度也很快,因为QList在其内部数组的两端预先分配了内存。需要注意的是,对于大于指针的非list 项,每次append 或 insert新的项都需要在堆上分配内存,如果需要这样的大量的插入和添加操作,这时最好选择QVector,因为QVector在单一的堆上分配内存。

 

需要注意的是:在list的生命期中,内部数组只有可能变大,不可能缩小。内部数组只能有析构函数释放或者当用一个list赋值给另外的list时,由赋值函数释放。

 

为了使QList尽可能高效,它的成员函数不验证输入的有效性。除了isEmpty()之外,其他的成员函数都假定list是非空的。使用索引参数的成员函数总是假定索引值是在有效的范围的。这意味着QList的函数可能调用失败。如果你在编译时定义了QT_NO_DEBUG,则将不会捕获这样的失败。如果没有定义QT_NO_DEBUG, Q_ASSERT() or Q_ASSERT_X() 将捕获这些失败弹出适当的信息。

 

为了避免失败,在调用其他成员函数前调用isEmpty()。如果成员函数用到索引参数,要检查索引是否在有效的范围。

和QVector类似,QList也是用的隐式共享。

 

QList<int>integerList;

integerList.push_back(1);

integerList.append(5);

 

//integerList.setSharable(false);

QList<int>List(integerList);

//List= integerList;

//integerList.setSharable(false);

 

cout<<"&List.at(0):"<<&List.at(0)<<endl;

cout<<"&integerList.at(0):"<<&integerList.at(0)<<endl;

技术分享

 

integerList.setSharable(false);取消注释之后显示的地址就不一样了

技术分享

 

 

std::list

std::list是一种顺序容器,它允许在其中的任何位置进行插入和删除操作,而且可以双向迭代。

List容器实现为双向链表,双向链表可以在不同而且不相关的位置进行存储其元素。其关联的顺序由一个指向前面元素的链接和一个指向后面元素的链接来保持的。

List类似于forward_list。最主要的不同就是forward_list是单链表,所以它只能前向迭代,因此也更小和更高效。

和其他基本的标准容器 (arrayvector and deque)相比,list在插入,提取,移动数据方面更高效,因此在密集的算法中一般都用list,比如排序算法。

和其他顺序容器相比,listsand forward_lists最大的缺点就是缺少通过位置直接存取元素的方法;它们也需要额外的内存来保持链接的信息。

QList 和std::list比较

构造函数:

QList构造函数:

QList::QList ()

QList::QList ( constQList<T> & other )

 

List构造函数:

C++98版:

explicit list (constallocator_type& alloc = allocator_type());

explicit list (size_type n, const value_type& val = value_type(), const allocator_type& alloc = allocator_type());
template <class InputIterator> list (InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type());
list (const list& x);

 

C++11版:

explicit list (const allocator_type& alloc = allocator_type());
explicit list (size_type n); 
list (size_type n, const value_type& val,  const allocator_type& alloc = allocator_type());
template <class InputIterator> list (InputIterator first, InputIterator last,
                                    const allocator_type& alloc = allocator_type());
list (const list& x);
list (const list& x, const allocator_type& alloc);
list (list&& x);
list (list&& x, const allocator_type& alloc);
list (initializer_list<value_type> il,
       const allocator_type& alloc = allocator_type());

QList的构造函数只有默认构造函数和拷贝构造函数两种,std::list的构造函数就比较多了。

 

QList特有的函数:

void QList::append ( const T & value )           在链表的末尾插入value

void QList::append ( constQList<T> & value )     在链表的末尾插入链表value的元素

该函数实际上调用了QList<T> &

operator+= ( const QList<T> & other )

 

bool QList::contains ( const T& value ) const      判断链表是否包含元素value

int QList::count ( const T& value ) const          统计链表中值为balue的元素个数

void QList::move ( int from,int to )   把索引为from的值移到索引为to的位置

 

QList<QString> list;

 list << "A" <<"B" << "C" << "D" <<"E" << "F";

 list.move(1, 4);

 // list: ["A", "C","D", "E", "B", "F"]

有关删除的一些操作:

 

void QList::removeAt (int i )

bool QList::removeOne ( const T & value )

void QList::removeFirst ()

void QList::removeLast ()

T QList::takeAt ( int i )

T QList::takeFirst ()

T QList::takeLast ()

 

与其他类型容器的转换方式:

QSet<T> QList::toSet () const

std::list<T> QList::toStdList ()const

QVector<T> QList::toVector () const

 

支持的操作符运算:

bool QList::operator!= ( constQList<T> & other ) const

QList<T> QList::operator+ (const QList<T> & other ) const

QList<T> & QList::operator+=( const QList<T> & other )

QList<T> & QList::operator+=( const T & value )

QList<T> &QList::operator<< ( const QList<T> & other )

QList<T> &QList::operator<< ( const T & value )

QList<T> & QList::operator=( const QList<T> & other )

bool QList::operator== ( constQList<T> & other ) const

T & QList::operator[] ( int i )

const T & QList::operator[] ( int i ) const

 

QDataStream & operator<< ( QDataStream & out, const QList<T> & list )

QDataStream & operator>> ( QDataStream & in, QList<T> & list )

 

Std::list特有的函数:

SpliceC++98版:

void splice (iterator position, list& x);
void splice (iterator position, list& x, iterator i);
void splice (iterator position, list& x, iterator first, iterator last);

C++11版:

void splice (const_iterator position, list& x);
void splice (const_iterator position, list&& x);
void splice (const_iterator position, list& x, const_iterator i);
void splice (const_iterator position, list&& x, const_iterator i);
void splice (const_iterator position, list& x, const_iterator first, const_iterator last);
void splice (const_iterator position, list&& x, const_iterator first, const_iterator last);

该函数个功能是:把链表x的元素,从x中转移到该链表中,从位置position进行插入。该操作不会调用任何元素的构造函数或析构函数。会同时改变这两个链表的大小。

std::list<int>mylist1, mylist2;

std::list<int>::iteratorit;

for(int i=1; i<=4; ++i)

         mylist1.push_back(i);   

for(int i=1; i<=3; ++i)

         mylist2.push_back(i*10); 

it =mylist1.begin();

++it;                       

mylist1.splice(it, mylist2);

cout<<"mylist1.size():"<<mylist1.size()<<endl;

cout<<"mylist2.size():"<<mylist2.size()<<endl;

it =mylist1.begin();

cout<<"mylist1:";

for(it; it !=mylist1.end(); ++it)

{

         cout<<*it<<" ";

}

cout<<endl;

it =mylist2.begin();

cout<<"mylist2:";

for(it; it !=mylist2.end(); ++it)

{

         cout<<*it<<" \t";

}

 技术分享

 

sort操作

void sort();
template <class Compare>
  void sort (Compare comp);
版本1用的是 < 比较操作,版本2用comp 进行比较。这两个排序进行的是严格的弱排序。对与相同的值是稳定的,排序后相对位置不变。元素在容器中进行移动,整个过程不会调用任何构造函数,析构函数或拷贝任何元素。

 

Unique操作:

void unique();
template <class BinaryPredicate>
  void unique (BinaryPredicate binary_pred);
不带参数的版本1会删除每一组相同值的除了第一个元素之外的元素,例如,有连续的几个值为 a  a  a,它会删除后面的两个a,值保留第一个a。
版本2用binary_pred作为比较函数,需要注意的是,该函数会为每个比较对调用binary_pred(*i,*(i-1)),如果比较返回true则会从链表中删除i。

boolsame_integral_part (double first, double second)

{

         return ( int(first)==int(second) );

}

structis_near

{

         bool operator() (double first, doublesecond)

         {

                   return(fabs(first-second)<5.0);

         }

};

 

         double mydoubles[]={ 12.15,  2.72, 73.0, 12.77,  3.14,

                   12.77, 73.35, 72.25,15.3,  72.25 };

         std::list<double> mylist(mydoubles,mydoubles+10);

 

         mylist.sort();            

         std::list<double>::iterator it =mylist.begin();

         cout<<"after sort() mylist:";

         int i = 0;

         for (it; it != mylist.end(); ++it, ++i)

         {

                   cout<<*it<<"  ";

                   if (i == 5)

                   {

                            cout<<endl;

                   }

         }

         cout<<endl;

 

         mylist.unique();

         it = mylist.begin();

         cout<<"after unique() mylist:";

         for (it; it != mylist.end(); ++it)

         {

                   cout<<*it<<"  ";

         }

         cout<<endl;

         mylist.unique (same_integral_part);

         it = mylist.begin();

         cout<<"after unique(same_integral_part) mylist :";

         for (it; it != mylist.end(); ++it)

         {

                   cout<<*it<<"  ";

         }

         cout<<endl;

 

         mylist.unique (is_near());         

         it = mylist.begin();

         cout<<"after unique(same_integral_part) mylist :";

         for (it; it != mylist.end(); ++it)

         {

                   cout<<*it<<"  ";

         }

         cout<<endl;

 

 技术分享

merge 操作:

C++98版本:
void merge (list& x);
template <class Compare>
  void merge (list& x, Compare comp);
 
C++11版本:
void merge (list& x);
  void merge (list&& x);
template <class Compare>
void merge (list& x, Compare comp);
template <class Compare>
  void merge (list&& x, Compare comp);
该函数把x的元素按适当的顺序合并到链表中,前提是两个链表都是已经排序了的。
该操作会移除x中的元素插入到链表中,和splice一样,它不会调用构造函数或者析构函数,仅仅是做了转移而已。
版本2指定了一个比较操作函数,它对元素进行严格的弱排序。调用该函数,链表必须是已经排序的,对于没有排序的链表,可以用splice。
对于相同的值也是稳定的,其位置和在x中的相对位置一样。

boolmycomparison (double first, double second)

{

         return ( int(first)<int(second) );

}

 

std::list<double>first, second;

         first.push_back (3.1);

         first.push_back (2.2);

         first.push_back (2.9);

 

         second.push_back (3.7);

         second.push_back (7.1);

         second.push_back (1.4);

 

         first.sort();

         second.sort();

 

         first.merge(second);

         // (second is now empty)

         second.push_back (2.1);

         first.merge(second,mycomparison);

         std::cout << "after mergefirst contains:";

         for (std::list<double>::iteratorit=first.begin(); it!=first.end(); ++it)

                   std::cout << ‘ ‘<< *it;

         std::cout << ‘\n‘;

         std::cout << "after mergesecond contains  size:"<<second.size()<<endl;

技术分享

如果我们尝试把排序的两句代码注释掉,则会弹出失败的断言信息。在merge函数中会检查链表是否已经排序。

first.sort();

second.sort();

 

reverse操作:

C++98版本:

void reverse();

C++11版本:

void reverse() noexcept;

该函数对链表进行反转。

std::list<int>mylist;

         for (int i=1; i<10; ++i)

                   mylist.push_back(i);

         std::cout << " beforereverse mylist contains:"<<endl;

         for (std::list<int>::iteratorit=mylist.begin(); it!=mylist.end(); ++it)

                   std::cout << ‘ ‘<< *it;

         std::cout << ‘\n‘;

         mylist.reverse();

         std::cout << "after reversemylist contains:"<<endl;

         for (std::list<int>::iteratorit=mylist.begin(); it!=mylist.end(); ++it)

                   std::cout << ‘ ‘<< *it;

         std::cout << ‘\n‘;

 技术分享

http://blog.csdn.net/hai200501019/article/details/11747475

以上是关于QList 和std::list的比较的主要内容,如果未能解决你的问题,请参考以下文章

Qt6-QVector分析

空大括号是调用默认构造函数还是调用 std::initializer_list 的构造函数?

std::list 模板在其实例类型中是不是需要复制构造函数(或等效项)?

使用 boost 的 list_of 将 std::list 传递给构造函数不会编译

Boost Python 暴露 C++ 类,构造函数采用 std::list

std::initializer_list 私有构造函数是不是从编译器得到非常特殊的处理?