C++STL 系列(六):list容器详解与示例
list 基本概念
list链表是一种在物理存储上非连续,逻辑连续的存储结构,不同节点之间通过指针链接
链表的组成:由一系列node节点组成
node节点的组成:
- 数据域:存放数据元素
- 指针域:存放下一个node的地址
STL中的链表是一个双向循环链表,因此
- 每个node的指针域存放两个指针,prv指向前一个节点,next指向后一个节点
- 头节点的prv指向尾节点,尾节点的next指向头节点,形成循环
push_front push_back
front() back()
------ ------ ------ ------
| data | | data | | data | | data |
|------| |------| |------| |------|
| prv | ↘↗| prv | ↘↗| prv |↘↗| prv |
-| next | ↗↘| next | ↗↘| next |↗↘| next |--
| ------ ------ ------ ------ |
| ↑-------------------------------------------
---------------------------------------------↑
pop_front pop_back
begin() insert() end()
由于链表的内存存储并不是连续的内存空间,只能通过指针来向前或向后查询,无法随机读取,因此链表的迭代器为 双向迭代器
list优点:
- 添加数据只需要申请必要的大小,不会造成内存浪费和溢出
- 链表执行插入和删除操作很方便,只需要修改指针而不用搬运数据
list缺点:
- 无法随机访问,空间(存放指针)和时间(指针间接寻址遍历)额外开销大
注意:list有一个重要的性质,插入和删除的操作不会使原来的迭代器失效,这在vector中是不成立的(元素移动,新空间移动)
STL中list和vector都是非常常用的,各有优缺点
list 构造函数
-
list<T> lst;// 默认构造函数 -
list(beg, end);// 构造函数将[beg, end)区间中的元素拷贝给本身 -
list(n, elem); // 构造函数将n个elem拷贝给本身。 -
list(const list &lst);// 拷贝构造函数 -
示例
// list的构造函数 /** * list<T> lst; // 默认构造函数 * list(beg, end); // 构造函数将[beg, end)区间中的元素拷贝给本身。 * list(n, elem); // 构造函数将n个elem拷贝给本身。 * list(const list &lst); // 拷贝构造函数 */ #include <iostream> #include <list> using namespace std; void print_list(const list<int>& l) { for (list<int>::const_iterator it = l.begin(); it != l.end(); it++) { cout << *it << " "; } cout << endl; } void test0() { // 1. 默认构造 list<int> l1; l1.push_back(10); l1.push_back(20); l1.push_back(30); l1.push_back(40); cout << "l1 = "; print_list(l1); // 2. 将[beg, end)区间中的元素拷贝给本身。 list<int> l2(l1.begin(), l1.end()); cout << "l2 = "; print_list(l2); // 3. 构造函数将n个elem拷贝给本身。 list<int> l3(3, 66); cout << "l3 = "; print_list(l3); // 4. 拷贝构造 list<int> l4(l3); cout << "l4 = "; print_list(l4); } int main() { test0(); return 0; }
list 赋值和交换
-
list& operator=(const list &lst);// 重载等号操作符 -
assign(beg, end);// 将[beg, end)区间中的数据拷贝赋值给本身。 -
assign(n, elem);// 将n个elem拷贝赋值给本身。 -
swap(lst);// 与另一个list交换 -
示例
// list的赋值和交换 /** * list& operator=(const list &lst); // 重载等号操作符 * assign(beg, end); // 将[beg, end)区间中的数据拷贝赋值给本身。 * assign(n, elem); // 将n个elem拷贝赋值给本身。 * swap(lst); // 将lst与本身的元素互换。 */ #include <iostream> #include <list> using namespace std; void print_list(const list<int>& l) { for (list<int>::const_iterator it = l.begin(); it != l.end(); it++) { cout << *it << " "; } cout << endl; } void test0() { list<int> l1; // 1. assign(n, elem) l1.assign(5, 66); cout << "l1 = "; print_list(l1); list<int> l2; // 2. assign(beg, end) l2.assign(l1.begin(), l1.end()); cout << "l2 = "; print_list(l2); list<int> l3; // 3. operator= l3 = l1; cout << "l3 = "; print_list(l3); list<int> l4; // 4. assign(n, elem) l4.assign(3, 88); cout << "l4 = "; print_list(l4); // 5. swap l1.swap(l4); cout << "after swap" << endl; cout << "l1 = "; print_list(l1); cout << "l4 = "; print_list(l4); } int main() { test0(); return 0; }
list 大小操作
-
size();// 返回容器中元素的个数 -
empty();// 判断容器是否为空 -
resize(num);// 重新指定容器的长度为num,若容器变长,则以默认值填充新位置。 -
resize(num, elem);// 重新指定容器的长度为num,若容器变长,则以elem值填充新位置。 -
示例
// list的大小操作 /** * size(); // 返回容器中元素的个数 * empty(); // 判断容器是否为空 * resize(num); // 重新指定容器的长度为num,若容器变长,则以默认值填充新位置。 * resize(num, elem); // 重新指定容器的长度为num,若容器变长,则以elem值填充新位置。 * */ #include <iostream> #include <list> using namespace std; void print_list(const list<int>& l) { for (list<int>::const_iterator it = l.begin(); it != l.end(); it++) { cout << *it << " "; } cout << endl; } void test0() { list<int> l1; l1.push_back(10); l1.push_back(20); l1.push_back(30); l1.push_back(40); cout << "the size of l1 is: " << l1.size() << endl; cout << "l1 = "; print_list(l1); // 1. resize(num) l1.resize(10); cout << "the size of l1 is: " << l1.size() << endl; cout << "l1 = "; print_list(l1); // 2. resize(num, elem) l1.resize(15, 100); cout << "the size of l1 is: " << l1.size() << endl; cout << "l1 = "; print_list(l1); } int main() { test0(); return 0; }
list 插入和删除
-
push_back(elem);// 尾插 -
pop_back();// 尾删 -
push_front(elem);// 头插 -
pop_front();// 头删 -
insert(pos, elem);// 在pos位置插入elem元素的拷贝,返回新数据的位置。 -
insert(pos, n, elem);// 在pos位置插入n个elem元素的拷贝,返回新数据的位置。 -
insert(pos, beg, end);// 在pos位置插入[beg, end)区间中的数据,返回新数据的位置 -
erase(beg, end);// 删除[beg, end)区间中的数据,返回下一个数据的位置。 -
erase(pos);// 删除pos位置的数据,返回下一个数据的位置。 -
remove(elem);// 删除容器中所有与elem值匹配的元素。 -
clear();// 清空 -
示例
// list的插入和删除 /** * push_back(elem); // 尾插 * pop_back(); // 尾删 * push_front(elem); // 头插 * pop_front(); // 头删 * insert(pos, elem); // 在pos位置插入elem元素的拷贝,返回新数据的位置。 * insert(pos, n, elem); // 在pos位置插入n个elem元素的拷贝,返回新数据的位置。 * insert(pos, beg, end); // 在pos位置插入[beg, end)区间中的数据,返回新数据的位置。 * erase(beg, end); // 删除[beg, end)区间中的数据,返回下一个数据的位置。 * erase(pos); // 删除pos位置的数据,返回下一个数据的位置。 * remove(elem); // 删除容器中所有与elem值匹配的元素。 * clear(); // 清空 */ #include <iostream> #include <list> using namespace std; void print_list(const list<int>& l) { for (list<int>::const_iterator it = l.begin(); it != l.end(); it++) { cout << *it << " "; } cout << endl; } void test0() { list<int> l1; l1.push_back(20); l1.push_back(20); l1.push_back(30); l1.push_front(100); l1.push_front(200); l1.push_front(300); cout << "l1 = "; print_list(l1); // 2. pop_back l1.pop_back(); l1.pop_front(); cout << "l1 = "; print_list(l1); // 3. insert(pos, elem) l1.insert(l1.begin(), 1000); cout << "l1 = "; print_list(l1); // 4. insert(pos, n, elem) l1.insert(l1.end(), 2, 2000); cout << "l1 = "; print_list(l1); // 5. erase(pos) l1.erase(l1.begin()); cout << "l1 = "; print_list(l1); // 6. remove(elem) l1.remove(20); cout << "l1 = "; print_list(l1); // 7. clear() l1.clear(); cout << "l1 = "; print_list(l1); } int main() { test0(); return 0; }
list 数据存取
-
front();// 返回第一个元素。 -
back();// 返回最后一个元素。 -
不可以使用at和[ ],因为list不支持随机访问。
-
示例
// list的数据存取 /** * front(); // 返回第一个元素。 * back(); // 返回最后一个元素。 * 不可以使用at和[],因为list不支持随机访问。 */ #include <iostream> #include <list> using namespace std; void test0() { list<int> l1; l1.push_back(10); l1.push_back(20); l1.push_back(30); l1.push_front(100); l1.push_front(200); l1.push_front(300); // 1. front() cout << "the first element of l1 is: " << l1.front() << endl; // 2. back() cout << "the last element of l1 is: " << l1.back() << endl; // 3. at(can not be used) // cout << "the first element of l1 is: " << l1.at(0) << endl; // 4. [](can not be used) // cout << "the first element of l1 is: " << l1[0] << endl; } int main() { test0(); return 0; }
list 反转和排序
-
reverse();// 反转 -
sort();// 排序 - 成员函数 -
对于不支持随机访问的迭代器,容器会提供相应的排序成员函数
-
默认升序,可以通过传入回调函数,实现降序排序
-
对于自定义数据类型,标准库并没有提供默认实现,需要传入回调函数,实现自定义的排序规则(见下一节自定义排序)
-
示例
// list的反转和排序 /** * reverse(); // 反转 * sort(); // 排序 - 成员函数 * 对于不支持随机访问的迭代器,容器会提供相应的排序成员函数 * 默认升序,可以通过传入回调函数,实现降序排序 * 对于自定义数据类型,标准库并没有提供默认实现,需要传入回调函数,实现自定义的排序规则(见07_list自定义排序) */ #include <iostream> #include <list> using namespace std; bool my_compare(int num1, int num2) { return num1 > num2; } void print_list(const list<int>& l) { for (list<int>::const_iterator it = l.begin(); it != l.end(); it++) { cout << *it << " "; } cout << endl; } void test0() { list<int> l1; l1.push_back(10); l1.push_back(20); l1.push_back(30); l1.push_front(100); l1.push_front(200); l1.push_front(300); cout << "l1 = "; print_list(l1); // reverse l1.reverse(); cout << "after reverse, l1 = "; print_list(l1); // sort l1.sort(); cout << "after sort, l1 = "; print_list(l1); // 降序 sort l1.sort(my_compare); cout << "after sort(my_compare), l1 = "; print_list(l1); } int main() { test0(); return 0; }
list 自定义数据排序
-
bool compare(const Person& p1, const Person& p2);// 比较函数 -
对于自定义数据类型,标准库并没有提供默认实现,需要传入回调函数,实现自定义的排序规则
-
案例描述:将Person自定义数据类型进行排序,Person中属性有姓名,年龄,身高
-
排序规则:按照年龄进行升序,如果年龄相同按照身高进行降序
-
示例
// list自定义数据排序 /** * bool compare(const Person& p1, const Person& p2); // 比较函数 * 对于自定义数据类型,标准库并没有提供默认实现,需要传入回调函数,实现自定义的排序规则 * 案例描述:将Person自定义数据类型进行排序,Person中属性有姓名,年龄,身高 * 排序规则:按照年龄进行升序,如果年龄相同按照身高进行降序 */ #include <iostream> #include <list> using namespace std; class person { public: person(string name, int age, int height) : m_name(name), m_age(age), m_height(height) {} string m_name; int m_age; int m_height; }; void print_list(const list<person>& l) { for (list<person>::const_iterator it = l.begin(); it != l.end(); it++) { cout << "name: " << (*it).m_name << " age: " << (*it).m_age << " height: " << (*it).m_height << endl; } cout << "--------------------------------" << endl; } bool my_compare(const person &p1, const person &p2) { // 先判断年龄 年龄一致则判断身高 if (p1.m_age != p2.m_age) { // 年龄升序 return p1.m_age < p2.m_age; } else { // 年龄降序 return p1.m_height > p2.m_height; } } void test0() { list<person> l; // push l.push_back(person("Mask", 18, 180)); l.push_back(person("Jack", 20, 175)); l.push_back(person("Rose", 19, 170)); l.push_back(person("Lily", 18, 160)); l.push_back(person("Lucy", 18, 165)); print_list(l); // sort l.sort(my_compare); print_list(l); } int main() { test0(); return 0; }
更多推荐

所有评论(0)