C++ list总结

简介: C++ list总结

目录


介绍  


常用函数


函数使用举例


创建list并赋值


遍历和查找


删除元素


清空列表


向list中插入元素


使用assign给容器增加新元素


两个list交换


使用resize改变list的大小。


使用splice函数操作list


删除重复的元素


合并list


排序


list和vector的区别


介绍  

list是线性双向链表结构,它的数据由若干个节点构成,每一个节点都包括一个信息块(即实际存储的数据)、一个前驱指针和一个后驱指针。它无需分配指定的内存大小且可以任意伸缩,这是因为它存储在非连续的内存空间中,并且由指针将有序的元素链接起来。由于其结构的原因,list 随机检索的性能非常的不好,因为它不像vector 那样直接找到元素的地址,而是要从头一个一个的顺序查找,这样目标元素越靠后,它的检索时间就越长。检索时间与目标元素的位置成正比。虽然随机检索的速度不够快,但是它可以迅速地在任何节点进行插入和删除操作。因为list 的每个节点保存着它在链表中的位置,插入或删除一个元素仅对最多三个元素有所影响,不像vector 会对操作点之后的所有元素的存储地址都有所影响,这一点是vector 不可比拟的。

tt.png



t 的特点:


(1) 不使用连续的内存空间,这样可以随意地进行动态操作;

(2) 可以在内部任何位置快速地插入或删除,当然也可以在两端进行push 和pop 。

(3) 不能进行内部的随机访问,即不支持[ ] 操作符和vector.at() ;

(4) 相对于verctor 占用更多的内存。


常用函数

List的构造函数和析构函数


list<Elem> c


产生一个空list,其中没有任何元素


list<Elem> c1(c2)


产生另一个同型list的副本(所有的元素都被拷贝)


list<Elem> c(n)


利用元素的default构造函数产生一个大小为n的list


list<Elem> c(n,elem)


产生一个大小为n的list,每个元素值都是elem


list<Elem> c(beg, end)


产生一个list,以区间[beg, end)做为元素初值


c.~list<Elem>()        


销毁所有元素,并释放内存


list的非变动性操作


size()


返回容器的大小


empty()  


判断容器是否为空,等价于size()==0,但可能更快


max_size()


返回容器最大的可以存储的元素


reserve()


如果容量不足,扩大之


c1 == c2


判断c1 是否等于c2


c1 != c2


判断c1是否不等于c2


c1 < c2


判断c1 是否小于c2


c1 > c2


判断c1 是否大于c2


c1 <= c2  


判断c1是否小于等于c2


c1 >= c2  


判断c1是否大于等于c2


list的赋值操作


c1 = c2    


将c2的全部元素赋值给c1


assign(n, elem)


复制n个elem,复制给c


assign(beg, end)    


将区间[beg;end)内的元素赋值给c


c1.swap(c2)


将c1和c2元素互换


swap(c1,c2)


同上,此为全局函数


元素访问


front        


返回第一个元素,不检查元素存在与否


back


返回最后一个元素,不检查元素存在与否


迭代器相关函数


begin()


返回一个双向迭代器,指向第一个元素


end()


返回一个双向迭代器,指向最后一个元素的下一个位置


rbegin()  


返回一个逆向迭代器,指向逆向迭代的第一个元素


end()


返回一个逆向迭代器,指向逆向迭代的最后一个元素的下一个位置


list安插、移除操作函数



insert(pos, elem)


在迭代器pos所指位置上安插一个elem副本,并返回新元素的位置


insert(pos,n,elem)


在pos位置上插入n个elem副本,无返回值


insert(pos,beg,end)


在pos位置上插入区间[beg,end)内的所有元素的副本,没有返回值


push_back(elem)


在尾部添加一个elem副本


pop_back()


移除最后一个元素,无返回值


push_front()    


在头部添加一个elem副本


pop_front()      


移除第一个元素,但不返回


remove(val)


移除所有其值为val的元素


remove_if()


删除一个链表中所有满足条件的元素


erase(pos)


移除pos位置上的元素,返回下一个元素的位置


erase(beg, end)


移除[beg, end)区间内的所有元素,返回下一个元素的位置


resize(num)


将元素数量改为num(如果size()变大了,多出来的新元素都需以default构造函数完成)


resize(num,elem)  


将元素数量改为num(如果size()变大了,多出来的新元素都elem的副本)


clear()      


移除所有元素,将容器清空


备注:安插和移除元素,都会使“作用点”之后的各个元素的iterator等失效,若发生内存重新分配,该容器身上的所有iterator等都会失效


List的特殊变动性操作


unique()


如果存在若干相邻而数值相等的元素,就移除重复元素,


之留下一个    


unique(op)      


如果存在若干相邻元素,都使op()的结果为ture,


则移除重复元素,只留下一个。


c1.splice(pos, c2)


将c2内的所有元素转移到c1之内,迭代器pos之前


c1.splice(pos, c2, c2pos)    


将c2内的c2pos所指元素转移到c1之内的pos所指位置上


(c1,c2可相同)


c1.splice(pos, c2,c2beg,c2end)  


将c2内的[c2beg,c2end)区间内所有元素转移到


c1内的pos之前(c1,c2可相同)


sort()


以operator<为准则,对所有元素排序


sort(op)


以op()为准则,对所有元素排序


c1.merge(c2)  


假设c1和c2容器都包含已序(相同的排序方式)元素,将c2的全部元素转移到c1,并保证合并后的list还是已序。


c1.merge(c2,op)


假设c1和c2容器都包含op()原则下的已序(相同的排序方式)元素,将c2的全部元素转移到c1,并保证合并后的list在op()原则仍是已序。



reverse()


将所有元素反序


函数使用举例

创建list并赋值

#include <iostream>


#include <list>


using namespace std;


int main() {


   //第一种,通过构造函数


   int myints[] = { 44,77,22,11,12 };


   list<int> mylist1(myints, myints + 5);


   list<int> mylist2(2, 100);         // 2个值为100的元素


   //第二种,用push_back,或push_front


   for (int i = 1; i <= 5; ++i) mylist1.push_back(i);


   mylist2.push_front(20);


   mylist2.push_front(30);


   //第三种,用assign


   list<int> first;


   list<int> second;


   first.assign(7, 10);                       // 给first添加7个值为10的元素


   second.assign(first.begin(), first.end()); // 复制first给second


   int myints1[] = { 32, 8, 4 };


   first.assign(myints1, myints1 + 3);         // 将数组myints的内容添加给first


   return 0;


}


遍历和查找

#include <iostream>


#include <list>


using namespace std;


int main() {


   //第一种,通过构造函数


   int myints[] = { 44,77,22,11,12};


   list<int> myList(myints, myints + 5);


   cout << "mylist contains:";


   //遍历


   for (list<int>::iterator it = myList.begin(); it != myList.end(); ++it)


   {


       cout << " " << *it;


   }


   cout << "\n";


   //查找


   for (list<int>::iterator it = myList.begin(); it != myList.end(); ++it)


   {


       if (*it == 22)


       {


           cout << "存在22";


       }


   }


   cout << "\n";


   //追加


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


       myList.push_back(i);


   //逆序遍历


   for (list<int>::reverse_iterator rit = myList.rbegin(); rit != myList.rend(); ++rit)


         cout << ' ' << *rit;


   return 0;


}


删除元素


// 创建实例以及赋值


#include <iostream>


#include <list>


using namespace std;


bool single_digit(const int& value) { return (value < 20); }


struct is_odd {


   //重载操作符 ()


   bool operator() (const int& value) { return (value % 2) == 1; }


};


int main() {


   //第一种,通过构造函数


   int myints[] = { 44,77,22,11,12 };


   list<int> myList(myints, myints + 5);


   cout << "mylist contains:";


   //遍历


   for (list<int>::iterator it = myList.begin(); it != myList.end(); ++it)


   {


       cout << " " << *it;


   }


   cout << "\n";


   //remove和remove_if删除元素


   myList.remove(22);


   myList.remove_if(single_digit);


   myList.remove_if(is_odd());


   //遍历


   for (list<int>::iterator it = myList.begin(); it != myList.end(); it++)


   {


       cout << " " << *it;


   }


   cout << "\n";


   //追加


   myList.push_back(22);


   for (list<int>::iterator it = myList.begin(); it != myList.end(); it++) {


       cout << " " << *it;


   }


   cout << "\n";


   //遍历删除,这是一种错误的写法。


   /*for (auto it = myList.begin(); it != myList.end(); it++)


   {


       if (*it == 11) {


            myList.erase(it);


       }


   }*/


   //第一种写法


   for (auto it = myList.begin(); it != myList.end();)


   {


       if (*it == 22) {


           myList.erase(it++);


       }


       else


       {


           cout << " " << *it;


           it++;


       }


   }


   //第二种写法


   for (auto it = myList.begin(); it != myList.end();)


   {


       if (*it == 22) {


           it=myList.erase(it);


       }


       else


       {


           cout << " " << *it;


           it++;


       }


   }


   return 0;


}


清空列表

#include <iostream>


#include <list>


using namespace std;


int main() {


   list<int> mylist;


   list<int>::iterator it;


   mylist.push_back(10);


   mylist.push_back(20);


   mylist.push_back(30);


   cout << "mylist contains:";


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


       cout << ' ' << *it;


   cout << '\n';


   mylist.clear();


   mylist.push_back(2121);


   mylist.push_back(3232);


   cout << "mylist contains:";


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


       cout << ' ' << *it;


   cout << '\n';


   return 0;


}


向list中插入元素

#include <iostream>


#include <list>


#include <vector>


using namespace std;


int main() {


   list<int> mylist;


   list<int>::iterator it;


   // 初始化


   for (int i = 1; i <= 5; ++i) mylist.push_back(i); // 1 2 3 4 5


   it = mylist.begin();


   ++it;       // 迭代器it现在指向数字2                      ^


   //在i0t指向的位置出插入元素10


   mylist.insert(it, 10);  // 1 10 2 3 4 5


   // "it" 仍然指向数字2                                   ^


   //在it指向的位置出插入两个元素20


   mylist.insert(it, 2, 20); // 1 10 20 20 2 3 4 5


   --it;       // 现在it指向数字20                             ^


   vector<int> myvector(2, 30); //创建vector容器,并初始化为含有2个值为30的元素


   //将vector容器的值插入list中


   mylist.insert(it, myvector.begin(), myvector.end());


   // 1 10 20 30 30 20 2 3 4 5


//it仍然指向数字20                            //               ^


   cout << "mylist contains:";


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


       cout << ' ' << *it;


   cout << '\n';


   return 0;


}


使用assign给容器增加新元素

#include <iostream>


#include <list>


using namespace std;


int main() {


   list<int> first;


   list<int> second;


   first.assign(7, 10);// 给first添加7个值为10的元素


   second.assign(first.begin(), first.end()); // 复制first给second


   int myints[] = { 22, 33, 44 };


   first.assign(myints, myints + 3);  // 将数组myints的内容添加给first


   cout << "Size of first: " << int(first.size()) << '\n';


   cout << "Size of second: " << int(second.size()) << '\n';


   return 0;


}


两个list交换

// swap lists


#include <iostream>


#include <list>


using namespace std;


int main() {


   list<int> first(3, 100);   // 三个值为100的元素


   list<int> second(5, 200);  // 五个值为200的元素


   first.swap(second);


   cout << "first contains:";


   for (list<int>::iterator it = first.begin(); it != first.end(); it++)


       cout << ' ' << *it;


   cout << '\n';


   cout << "second contains:";


   for (list<int>::iterator it = second.begin(); it != second.end(); it++)


       cout << ' ' << *it;


   cout << '\n';


   return 0;


}


使用resize改变list的大小。

// resizing list


#include <iostream>


#include <list>


using namespace std;


int main() {


   list<int> mylist;


   // 初始化


   for (int i = 1; i < 10; ++i) mylist.push_back(i);//list为0 1 2 3 4 5 6 7 8 9


   mylist.resize(5);//list的长度变为5,元素为:0 1 2 3 4


   mylist.resize(8, 100);//list的长度变为8,超过5的部分变为100,元素为:0 1 2 3 4 100 100 100


   mylist.resize(12);//list的长度变为12,超过5的部分赋默认值0,元素为:0 1 2 3 4 100 100 100 0 0 0 0


   cout << "mylist contains:";


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


       cout << ' ' << *it;


   cout << '\n';


   return 0;


}


使用splice函数操作list

// splicing lists


#include <iostream>


#include <list>


using namespace std;


int main() {


   list<int> mylist1, mylist2;


   list<int>::iterator it;


   // 初始化


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


       mylist1.push_back(i);      // mylist1: 1 2 3 4 5 6 7 8 9


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


       mylist2.push_back(i * 10);   // mylist2: 10 20 30


   it = mylist1.begin();


   ++it;                         // 指向数字2


   mylist1.splice(it, mylist2); // mylist1: 1 10 20 30 2 3 4


                                 // mylist2 (empty)


                                 // "it" 仍然指向数字2


   mylist2.splice(mylist2.begin(), mylist1, it);


   // mylist1: 1 10 20 30 3 4


   // mylist2: 2


   // "it" 此时已经无效了


   it = mylist1.begin();


   advance(it, 3);           // "it" 指向数字30


   mylist1.splice(mylist1.begin(), mylist1, it, mylist1.end());


   // mylist1: 30 3 4 1 10 20


   cout << "mylist1 contains:";


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


       cout << ' ' << *it;


   cout << '\n';


   cout << "mylist2 contains:";


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


       cout << ' ' << *it;


   cout << '\n';


   return 0;


}



删除重复的元素

// list::unique


#include <iostream>


#include <cmath>


#include <list>


using namespace std;


// a binary predicate implemented as a function:


bool same_integral_part(double first, double second) { return (int(first) == int(second)); }



// a binary predicate implemented as a class:


struct is_near {


   bool operator() (double first, double second) { return (fabs(first - second) < 5.0); }


};



int main() {


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


                      12.77, 73.35, 72.25, 15.3, 72.25 };


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


   cout << "mylist contains:";


   for (list<double>::iterator it = mylist.begin(); it != mylist.end(); ++it)


       cout << ' ' << *it;


   cout << '\n';


   mylist.unique();


   cout << "mylist contains:";


   for (list<double>::iterator it = mylist.begin(); it != mylist.end(); ++it)


       cout << ' ' << *it;


   cout << '\n';


   mylist.sort();             //  2.72,  3.14, 12.15, 12.77, 12.77,


                            // 15.3,  72.25, 72.25, 73.0,  73.35


   mylist.unique();           //  2.72,  3.14, 12.15, 12.77


                            // 15.3,  72.25, 73.0,  73.35


   cout << "mylist contains:";


   for (list<double>::iterator it = mylist.begin(); it != mylist.end(); ++it)


       cout << ' ' << *it;


   cout << '\n';


   mylist.unique(same_integral_part);  //  2.72,  3.14, 12.15                                 // 15.3,  72.25, 73.0


   cout << "mylist contains:";


   for (list<double>::iterator it = mylist.begin(); it != mylist.end(); ++it)


       cout << ' ' << *it;


   cout << '\n';


   mylist.unique(is_near());           //  2.72, 12.15, 72.25


   cout << "mylist contains:";


   for (list<double>::iterator it = mylist.begin(); it != mylist.end(); ++it)


       cout << ' ' << *it;


   cout << '\n';


   return 0;


}


合并list

#include <iostream>


#include <list>


using namespace std;


bool mycomparison(double first, double second) { return ((first) < (second)); }


int main() {


   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);


   cout << "first contains:";


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


       cout << ' ' << *it;


   cout << '\n';


   // (second 现在为空)


   second.push_back(1.1);


   second.push_back(2.1);


   second.push_back(2.5);


 


   first.merge(second, mycomparison);


   cout << "first contains:";


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


       cout << ' ' << *it;


   cout << '\n';


   return 0;


}


排序

// list::sort


#include <iostream>


#include <list>


#include <string>


#include <cctype>


using namespace std;


// comparison, not case sensitive.


bool compare_nocase(const string& first, const string& second) {


   unsigned int i = 0;


   while ((i < first.length()) && (i < second.length())) {


       //将大写字母转为小写字母


       if (tolower(first[i]) < tolower(second[i])) return true;


       else if (tolower(first[i]) > tolower(second[i])) return false;


       ++i;


   }


   return (first.length() < second.length());


}



int main() {


   list<string> mylist;


   list<string>::iterator it;


   mylist.push_back("one");


   mylist.push_back("two");


   mylist.push_back("Three");


   mylist.push_back("Four");


   mylist.push_back("Five");


   mylist.push_back("Six");


   mylist.sort();


   cout << "mylist contains:";


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


       cout << ' ' << *it;


   cout << '\n';


   mylist.sort(compare_nocase);


   cout << "mylist contains:";


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


       cout << ' ' << *it;


   cout << '\n';


   return 0;


}


list和vector的区别

vector数据结构

vector和数组类似,拥有一段连续的内存空间,并且起始地址不变。

因此能高效的进行随机存取,时间复杂度为o(1);

但因为内存空间是连续的,所以在进行插入和删除操作时,会造成内存块的拷贝,时间复杂度为o(n)。

另外,当数组中内存空间不够时,会重新申请一块内存空间并进行内存拷贝。

vector拥有一段连续的内存空间,能很好的支持随机存取,

因此vector<int>::iterator支持“+”,“+=”,“<”等操作符。


list数据结构

list是由双向链表实现的,因此内存空间是不连续的。

只能通过指针访问数据,所以list的随机存取非常没有效率,时间复杂度为o(n);

但由于链表的特点,能高效地进行插入和删除。

list的内存空间可以是不连续,它不支持随机访问,

因此list<int>::iterator则不支持“+”、“+=”、“<”等


vector<int>::iterator和list<int>::iterator都重载了“++”运算符。


总之,如果需要高效的随机存取,而不在乎插入和删除的效率,使用vector;

如果需要大量的插入和删除,而不关心随机存取,则应使用list。


参考:


1https://www.cnblogs.com/wj0816/p/6568630.html

 


tt.png

目录
相关文章
|
17小时前
|
编译器 C++ 容器
【C++/STL】:list容器的深度剖析及模拟实现
【C++/STL】:list容器的深度剖析及模拟实现
7 2
|
4天前
|
存储 算法 C++
C++一分钟之-容器概览:vector, list, deque
【6月更文挑战第21天】STL中的`vector`是动态数组,适合随机访问,但插入删除非末尾元素较慢;`list`是双向链表,插入删除快但随机访问效率低;`deque`结合两者优点,支持快速双端操作。选择容器要考虑操作频率、内存占用和性能需求。注意预分配容量以减少`vector`的内存重分配,使用迭代器而非索引操作`list`,并利用`deque`的两端优势。理解容器内部机制和应用场景是优化C++程序的关键。
19 5
|
17小时前
|
存储 C++ 容器
【C++/STL】:list容器的基本使用
【C++/STL】:list容器的基本使用
5 1
|
27天前
|
编译器 C语言 C++
从C语言到C++_33(C++11_上)initializer_list+右值引用+完美转发+移动构造/赋值(中)
从C语言到C++_33(C++11_上)initializer_list+右值引用+完美转发+移动构造/赋值
11 1
从C语言到C++_33(C++11_上)initializer_list+右值引用+完美转发+移动构造/赋值(中)
|
13天前
|
存储 C++
C++的list-map链表与映射表
这篇教程介绍了C++中`list`链表和`map`映射表的基本使用。`list`链表可通过`push_front()`、`push_back()`、`pop_front()`和`pop_back()`进行元素的添加和删除,使用迭代器遍历并支持在任意位置插入或删除元素。`map`是一个键值对的集合,元素自动按键值排序,可使用下标操作符或`insert()`函数插入元素,通过迭代器遍历并修改键值对,同时提供`count()`方法统计键值出现次数。教程中包含多个示例代码以帮助理解和学习。
15 2
|
19天前
|
存储 C++
C++初阶学习第十一弹——探索STL奥秘(六)——深度刨析list的用法和核心点
C++初阶学习第十一弹——探索STL奥秘(六)——深度刨析list的用法和核心点
22 7
|
27天前
|
存储 安全 C语言
从C语言到C++_33(C++11_上)initializer_list+右值引用+完美转发+移动构造/赋值(上)
从C语言到C++_33(C++11_上)initializer_list+右值引用+完美转发+移动构造/赋值
15 2
|
27天前
|
编译器 C语言 C++
从C语言到C++_33(C++11_上)initializer_list+右值引用+完美转发+移动构造/赋值(下)
从C语言到C++_33(C++11_上)initializer_list+右值引用+完美转发+移动构造/赋值
21 1
|
27天前
|
C语言 容器
从C语言到C++_17(list的模拟实现)list不是原生指针的迭代器(下 )
从C语言到C++_17(list的模拟实现)list不是原生指针的迭代器
10 1
|
27天前
|
C语言 计算机视觉
从C语言到C++_17(list的模拟实现)list不是原生指针的迭代器(中)
从C语言到C++_17(list的模拟实现)list不是原生指针的迭代器
14 1