C++list容器介绍

Posted Suk-god

tags:

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

文章目录

1、list介绍

  1. list是可以在常数范围内任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代
  2. list的底层是双向循环链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
  3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能向前迭代,以让其更简单高效。
  4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好
  5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)

2、list的底层结构

list的底层结构是一个带头节点的双向循环链表,它可以在任意位置插入或者删除一个元素。

双向:可以正序遍历也可以逆序遍历
循环:找尾结点的时间复杂度为O(1)
带头节点:
 ①代码实现简单;
 ②存放end()迭代器,end是最后一个元素的下一个位置;

3、list接口使用

3.1 构造&&析构

3.1.1 构造

1、explicit list (const allocator_type& alloc = allocator_type());

默认构造函数,构造出来一个仅有头节点的空链表

2、explicit list (size_type n, const value_type& val = value_type(),constallocator_type& alloc = allocator_type());

使用n个值为val的元素构造双向链表
对于val来说:

如果显式提供,就使用提供的值
未提供:内置类型,默认值为0,自定义类型,该类型必须要有默认构造函数

3、template <class InputIterator>
list (InputIterator first, InputIterator last,const allocator_type& alloc = allocator_type());

用区间[first,last)之间的元素来构造双向链表

4、list (const list& x);

拷贝构造函数

demo:

3.1.2 析构

~list();

用来释放资源,在对象使用完毕后会自动调用

3.1.3 赋值运算符重载

list& operator= (const list& x);

将一个双向链表赋值(拷贝)给另一个双向链表

demo:

3.2 迭代器

begin && end
iterator begin(); | const_iterator begin() const;
iterator end(); | const_iterator end() const;

begin:返回链表的第一个元素的位置
end:返回链表的最后一个元素的下一个位置(这里就是头节点的位置)

rbegin && rend
reverse_iterator rbegin(); | const_reverse_iterator rbegin() const;
reverse_iterator rend(); | const_reverse_iterator rend() const;

rbegin:返回end的位置
rend:返回begin的位置

注意 :这两组接口,每个都提供const和非const接口,原因是const对象无法调用非const成员函数,因此需要提供const接口供const对象使用。

demo:

void TestIterators1()

	int array[] =  1, 2, 3, 4, 5, 6, 7, 8, 9, 0 ;
	list<int> l1(array, array + sizeof(array) / sizeof(array[0]));

	const list<int>l2(array, array + sizeof(array) / sizeof(array[0]));
	//测试begin&&end
	cout << "Before:" << endl;
	for (auto iter = l1.begin(); iter != l1.end(); ++iter)
	
		cout << *iter << " ";
	
	cout << endl;

	auto it1 = l1.begin();
	*it1 = 100;
	auto it2 = l2.begin();
	// *it2 = 100;//错误写法,l2被const修饰,因此只能调用const成员方法,因此也就无法通过迭代器修改元素的值
	++it2;

	cout << "After:" << endl;
	for (auto iter = l1.begin(); iter != l1.end(); ++iter)
	
		cout << *iter << " ";
	
	cout << endl;
	//测试rbegin && rend
	cout << "rbegin && rend:" << endl;
	for (auto iter = l1.rbegin(); iter != l1.rend(); ++iter)
	
		cout << *iter << " ";
	
	cout << endl;


C++11
cbegin && cend
const_iterator cbegin() const noexcept;
const_iterator cend() const noexcept;

cbegin:返回链表的第一个元素的位置
cend:返回链表最后一个元素的下一个位置,也就是头节点的位置

crbegin && crend
const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;

crbegin:返回cend的位置
crend:返回crbegin的位置

注意:这两组接口的返回值指向的元素不可被修改

demo:

void TestIterators2()

	int array[] =  1, 2, 3, 4, 5, 6, 7, 8, 9, 0 ;
	list<int> l1(array, array + sizeof(array) / sizeof(array[0]));
	const list<int>l2(array, array + sizeof(array) / sizeof(array[0]));
	//测试cbegin&&cend
	cout << "Before:" << endl;
	for (auto iter = l1.cbegin(); iter != l1.cend(); ++iter)
	
		cout << *iter << " ";
	
	cout << endl;

	auto it1 = l1.cbegin();
	// *it1 = 100;//错误写法,cbegin返回值指向的元素不可被修改


	//测试crbegin && crend
	cout << "rbegin && rend:" << endl;
	for (auto iter = l1.crbegin(); iter != l1.crend(); ++iter)
	
		cout << *iter << " ";
	
	cout << endl;

3.3 容量相关

bool empty() const;
size_type size() const;

empty:判空,空–true
size–求链表有效元素个数

注意:list没有capacity和reserve方法

demo:

3.4 元素访问相关

reference front(); | const_reference front() const;
reference back(); | const_reference back() const;

front:获取链表的第一个元素
back:获取链表的最后一个元素

注意:list没有提供 operator[](size_t index)方法,因为list是带头节点的双向循环链表不支持随机访问

demo

3.5 修改相关

3.5.1 assign

将新内容分配给列表容器,替换其当前内容,并相应地修改其大小。

template <class InputIterator>
void assign (InputIterator first, InputIterator last);

使用区间[first,last)之间的元素从新构建新的容器

void assign (size_type n, const value_type& val);

使用n个值为val的元素重新构建新的容器

void resize (size_type n, value_type val = value_type());

将链表的有效元素调整为n个
记链表原来的有效元素个数为oldsize
n > oldsize,多出来的结点使用val来填充
n < oldsize,将链表的有效元素个数缩小至n
n == oldsize 不做任何操作

demo:

void TestAssign()

	int array[] =  1, 2, 4, 5, 5, 6, 56, 78, 65, 90 ;
	list<int> l(array, array + sizeof(array) / sizeof(array[0]));

	int temp[] =  100, 200, 300 ;
	l.assign(temp, temp + sizeof(temp) / sizeof(temp[0]));

	l.assign(10, -100);

3.5.2 头插 && 头删

void push_front (const value_type& val);

头插一个值为val的元素,时间复杂度O(1)\\

void pop_front();

头删一个节点,O(1)

demo:

3.5.3 尾插 && 尾删

void push_back (const value_type& val);

尾插一个值为val的元素,O(1)
void pop_back();
尾删,O(1)

demo:

3.5.4 任意位置插入

iterator insert (iterator position, const value_type& val);

在position位置插入元素val

void insert (iterator position, size_type n, const value_type& val);

在position位置插入n个值为val的元素

template <class InputIterator>
void insert (iterator position, InputIterator first, InputIterator last);

在position位置插入区间[first,last)的内容

demo:

3.5.5 任意位置删除

iterator erase (iterator position);

删除position位置的元素

iterator erase (iterator first, iterator last);

删除区间[first,last)之间的元素

demo:

3.5.6 swap && clear

void swap (list& x);

交换两个链表

void clear();

清空链表

demo:

以上就是对list的基本接口介绍及其使用~!下篇我们模拟实现list,敬请期待
!!!

以上是关于C++list容器介绍的主要内容,如果未能解决你的问题,请参考以下文章

C++list

手撕STLlist

C++:STL——List的模拟实现

List的实现总结

C++list容器介绍

C++中list的用法总结