cpp►STL容器->序列容器->list

Posted itzyjr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cpp►STL容器->序列容器->list相关的知识,希望对你有一定的参考价值。

描述

std::list
template <class T, class Alloc = allocator<T>> class list;
list是序列容器,允许在序列中的任何位置执行固定时间的插入和删除操作,并在两个方向上进行迭代。

list容器实现为双链接列表;双链接列表可以将其包含的每个元素存储在不同且不相关的存储位置。在内部,顺序是通过与每个元素的关联来保持的,每个元素都有链接指向它前面的元素,也有链接指向它后面的元素。

它们非常类似于forward_list:主要区别在于forward_list对象是单链表,因此它们只能向前迭代,以换取更小和更高效。

与其他基本标准序列容器(array、vector和deque)相比,list容器通常在迭代器的任何位置插入、提取和移动元素方面表现更好,因此在大量使用这些元素的算法(如排序算法)中也表现更好。

与其他序列容器相比,forward_list的主要缺点是它们无法通过位置直接访问元素;例如,要访问前向列表中的第六个元素,必须从开始到该位置进行迭代,这需要在这些元素之间的距离上花费线性时间。它们还消耗一些额外的内存来保持与每个元素相关联的链接信息(这可能是小size元素的大列表的一个重要因素)。

容器属性(Container properties)
  • Sequence
    序列容器中的元素按严格的线性序列排序。单个元素通过其在此序列中的位置进行访问。
  • Doubly-linked list
    每个元素都保存有关如何定位下一个和上一个元素的信息,允许在特定元素之前或之后进行固定时间的插入和擦除操作(即使是整个范围),但不允许直接随机访问。
  • Allocator-aware
    容器使用分配器对象动态处理其存储需求。
模板参数(Template parameters)
  • T
    元素的类型。别名是成员类型list::value_type。
  • Alloc
    用于定义存储分配模型的分配器对象的类型。默认情况下,使用分配器类模板,它定义了最简单的内存分配模型,并且与值无关。别名为成员类型list::allocator_type。

成员类型(Member types)------略
成员函数(Member functions)------略
迭代器(Iterators)------略
容量(Capacity)------略
访问元素(Element access)------略

修改器(Modifiers)
  • emplace_front
template <class... Args>
void emplace_front(Args&&... args)

构造及在开始位置插入元素。

// list::emplace_front
#include <iostream>
#include <list>
int main() {
	std::list<std::pair<int, char>> mylist;
	mylist.emplace_front(10, 'a');
	mylist.emplace_front(20, 'b');
	mylist.emplace_front(30, 'c');
	std::cout << "mylist contains:";
	for (auto& x : mylist)
		std::cout << " (" << x.first << "," << x.second << ")";
	return 0;
}
mylist contains: (30,c) (20,b) (10,a)
  • push_front
// list::push_front
#include <iostream>
#include <list>
int main() {
    std::list<int> mylist(2, 100);// two ints with a value of 100
    mylist.push_front(200);
    mylist.push_front(300);
    std::cout << "mylist contains:";
    for (std::list<int>::iterator it = mylist.begin(); it != mylist.end(); ++it)
        std::cout << ' ' << *it;
    return 0;
}
300 200 100 100
  • pop_front
// list::pop_front
#include <iostream>
#include <list>
int main() {
	std::list<int> mylist;
	mylist.push_back(100);
	mylist.push_back(200);
	mylist.push_back(300);
	std::cout << "Popping out the elements in mylist:";
	while (!mylist.empty()) {
		std::cout << ' ' << mylist.front();
		mylist.pop_front();
	}
	std::cout << "\\nFinal size of mylist is " << mylist.size();
	return 0;
}
Popping out the elements in mylist: 100 200 300
Final size of mylist is 0
操作(Operations)
  • splice /splaɪs/ 移接=移除+接合
entire list (1)	 
	void splice (iterator position, list& x);
single element (2)
	void splice (iterator position, list& x, iterator i);
element range (3)	
	void splice (iterator position, list& x, iterator first, iterator last);

entire list (1):将(list& x)的所有元素移接到容器中。
single element (2):只将(iterator i)所指的元素从(list& x)移接到容器中。
element range (3):将范围在[first,last]的(list& x)移接到容器中。

// splicing lists
#include <iostream>
#include <list>
int main() {
	std::list<int> mylist1, mylist2;
	std::list<int>::iterator it;
	for (int i = 1; i <= 4; ++i)
		mylist1.push_back(i);// mylist1: 1 2 3 4
	for (int i = 1; i <= 3; ++i)
		mylist2.push_back(i * 10);// mylist2: 10 20 30

	it = mylist1.begin();
	++it;// points to 2

	/* ➊entire list (1) */
	/* 将整个mylist2移接到mylist1的“it”所指位置 */
	/* mylist2全部移接到mylist1后,mylist2就没有元素了 */
	mylist1.splice(it, mylist2);
	// mylist1: 1 10 20 30 2 3 4
	// mylist2 (empty)
	// "it" still points to 2 (the 5th element)
	
	/* ➋single element (2) */
	/* 将“it”所指元素从mylist1移接到mylist2的begining位置 */
	/* 移接后,mylist1失去一个元素,mylist2增加一个元素 */
	mylist2.splice(mylist2.begin(), mylist1, it);
	// mylist1: 1 10 20 30 3 4
	// mylist2: 2
	// "it" is now invalid.
	
	it = mylist1.begin();
	std::advance(it, 3);// "it" points now to 30

	/* ➌element range (3) */
	/* 将区间[it, mylist1.end()]的mylist1移接到自己的begining位置 */
	/* mylist1的{30,3,4}移接到它的首位置,变为:30,3,4,1,10,20 */
	mylist1.splice(mylist1.begin(), mylist1, it, mylist1.end());
	// mylist1: 30 3 4 1 10 20

	std::cout << "mylist1 contains:";
	for (it = mylist1.begin(); it != mylist1.end(); ++it)
		std::cout << ' ' << *it;
	std::cout << '\\n';

	std::cout << "mylist2 contains:";
	for (it = mylist2.begin(); it != mylist2.end(); ++it)
		std::cout << ' ' << *it;
	return 0;
}
mylist1 contains: 30 3 4 1 10 20
mylist2 contains: 2
  • remove
    void remove(const value_type& val);
// remove from list
#include <iostream>
#include <list>
int main() {
	int myints[] = { 17,89,7,14 };
	std::list<int> mylist(myints, myints + 4);
	mylist.remove(89);
	std::cout << "mylist contains:";
	for (std::list<int>::iterator it = mylist.begin(); it != mylist.end(); ++it)
		std::cout << ' ' << *it;
	return 0;
}
mylist contains: 17 7 14
  • remove_if
    template <class Predicate> void remove_if(Predicate pred);
    参数pred:一元谓词,取与forward_list对象中包含的值类型相同的值,对于要从容器中删除的值返回true,对于剩余的值返回false。它可以是函数指针或函数对象。
// list::remove_if
#include <iostream>
#include <list>
// a 一元谓语 implemented as a 【function】:
bool single_digit(const int& value) {
	return (value < 10);
}
// a 一元谓语 implemented as a 【class】:
struct is_odd {
	bool operator() (const int& value) {
		return (value % 2) == 1;
	}
};
int main() {
	int myints[] = { 15,36,7,17,20,39,4,1 };
	std::list<int> mylist(myints, myints + 8);// 15 36 7 17 20 39 4 1

	mylist.remove_if(single_digit);// 15 36 17 20 39

	mylist.remove_if(is_odd());// 36 20

	std::cout << "mylist contains:";
	for (std::list<int>::iterator it = mylist.begin(); it != mylist.end(); ++it)
		std::cout << ' ' << *it;
	return 0;
}
mylist contains: 36 20
  • unique
    void unique();
    template <class BinaryPredicate> void unique<BinaryPredicate binary_pred);
    参数binary_pred:二元谓词,取两个与列表中包含的值类型相同的值,返回true以从容器中删除作为第一个参数传递的元素,否则返回false。这应该是函数指针或函数对象。

注意:该函数将为所有成对的元素(其中it是元素的迭代器,从第二个开始)调用binary_pred(*it, *(it-1)),如果谓词返回true,则从列表中删除it。

// list::unique
#include <iostream>
#include <cmath>
#include <list>
// a 二元谓语 implemented as a 【function】:
bool same_integral_part(double first, double second) {
	return (int(first) == int(second));
}
// a 二元谓语 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 };
	std::list<double> mylist(mydoubles, mydoubles + 10);

	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
	mylist.unique(same_integral_part);// 2.72, 3.14, 12.15
									  // 15.3, 72.25, 73.0
	mylist.unique(is_near());// 2.72, 12.15, 72.25
	std::cout << "mylist contains:";
	for (std::list<double>::iterator it = mylist.begin(); it != mylist.end(); ++it)
		std::cout << ' ' << *it;
	return 0;
}
mylist contains: 2.72 12.15 72.25

对于mylist:{2.72, 3.14, 12.15, 15.3, 72.25, 73.0},调用mylist.unique(isnear());时,从第2个元素开始,与前一个元素比较,如果<5,返回true,则删除第2个元素。否则删除前一个元素。(|3.14-2.72|<5)==true,删除3.14。同理,还要删除15.3、73.0,删除完毕。

  • merge
(1) void merge(list& x);
(2) template <class Compare>
    void merge(list& x, Compare comp);

作用:合并有序list。
通过将(list& x)的所有元素在其各自的已排序位置转移到容器中(两个容器都已排序好),将(list& x)合并到列表中。
这将有效地删除(list& x)中的所有元素(该元素变为空),并将它们插入到容器中的有序位置(容器的大小按传输的元素数扩展)。
参数comp:二元谓词,取与列表中包含的值类型相同的两个值,如果第一个参数被认为在它定义的严格弱顺序中先于第二个参数,则返回true,否则返回false。这应该是函数指针或函数对象。

// list::merge
#include <iostream>
#include <list>
// compare only integral part:
bool mycomparison(double first, double second) {
	return (int(first) < int(second));
}
int main() {
	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();// 2.2 2.9 3.1(merge的两个list得是ordered list)
	second.sort();// 1.4 3.7 7.1

	// merge后是ordered list
	first.merge(second);// first:1.4 2.2 2.9 3.1 3.7 7.1
                        // second:empty
	second.push_back(2.1);// second:2.1

	first.merge(second, mycomparison);
	std::cout << "first contains:";
	for (std::list<double>::iterator it = first.begin(); it != first.end(); ++it)
		std::cout << ' ' << *it;
	return 0;
}
first contains: 1.4 2.2 2.9 2.1 3.1 3.7 7.1

second:{2.1}这个元素依次与first:{1.4, 2.2, 2.9, 3.1, 3.7, 7.1}中每个元素比较,mycomparison(2.1, 1.4)==false,…,mycomparison(2.1, 3.1)==true,这时2.1就放在了3.1的前面。

  • sort
(1) void sort();
(2) template <class Compare>
	void sort(Compare comp);
// list::sort
#include <iostream>
#include <list>
#include <string>
#include <cctype>
// comparison, not case sensitive.
bool compare_nocase(const std::string& first, const std::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() {
	std::list<std::string> mylist;
	std::list<std::string>::iterator it;
	mylist.push_back("one");
	mylist.push_back("two");
	mylist.push_back("Three");

	mylist.sort();
	std::cout << "mylist contains:";
	for (it = mylist.begin(); it != mylist.end(); ++it)
		std::cout << ' ' << *it;
	std::cout << '\\n';

	mylist.sort(compare_nocase);
	std::cout << "mylist contains:";
	for (it = mylist.begin(); it != mylist.end(); ++it)
		std::cout << ' ' << *it;
	return 0;
}
mylist contains: Three one two
mylist contains: one Three two
  • reverse
    void reverse() noexcept;
// reversing list
#include <iostream>
#include <list>
int main() {
    std::list<int> mylist;
    for (int i = 1; i < 10; ++i) 
        mylist.push_back(i);
    mylist.reverse();
    std::cout << "mylist contains:";
    for (std::list<int>::iterator it = mylist.begin(); it != mylist.end(); ++it)
        std::cout << ' ' << *it;
    return 0;
}
mylist contains: 9 8 7 6 5 4 3 2 1

观察者(Observers)------略
非成员函数重载(Non-member function overloads)------略

以上是关于cpp►STL容器->序列容器->list的主要内容,如果未能解决你的问题,请参考以下文章

cpp►STL容器->序列容器->deque

cpp的stl有linklist吗

STL序列式容器之list

STL序列容器(list)

stl源码剖析-序列式容器 之 list

一文带你认识STL序列式容器--list