list常见接口的使用(基于c++标准库中的STL)

前言 

        list是重要的容器了解它的常见接口以及使用是很有必要的,为什么有了vector还要有list呢?因为vector存在一些缺陷,比如:容量满了要扩容,扩容是要付出代价的(性能的损失),存在空间的浪费,而且vector的头删头插或者中间位置的插入删除都需要挪动数据(时间复杂度O(n))因此比较慢。而list的存在就是为了弥补vector的缺点,list不需要扩容,不存在空间的浪费,任意位置的插入和删除都很快(时间复杂度为(O1))。下面让我们一起来了解一下list的使用吧!

目录

1.构造函数

2.迭代器

3.插入删除

4.容量相关

        4.1容量相关

        4.2取出表头表尾数据

5.list的迭代器失效


1.构造函数

         

例如:

void testList1()
{
	list<int>l1;//构造空的对象
	list<int>l2(5, 2);//构造5个val值的对象
	list<int>l3(l2);//拷贝构造

	//尾删尾插
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);
	l1.push_back(5);

	l1.pop_back();
	//迭代器正向遍历
	list<int>::iterator it = l1.begin();
	while (it != l1.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	//范围for
	for (auto e : l2)
	{
		cout << e << " ";
	}
}

2.迭代器

         

void testList1()
{
	list<int>l1;//构造空的对象
	list<int>l2(5, 2);//构造5个val值的对象
	list<int>l3(l2);//拷贝构造

	//尾删尾插
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);
	l1.push_back(5);

	l1.pop_back();
	//迭代器正向遍历
	list<int>::iterator it = l1.begin();
	while (it != l1.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	//范围for
	for (auto e : l2)
	{
		cout << e << " ";
	}
}
void print(const list<int>& l1);
void testList2()
{
	list<int> l1;
	//头插头删
	l1.push_front(0);
	l1.push_front(-1);
	l1.push_front(-2);
	l1.push_front(-3);
	l1.push_front(-4);
	l1.push_front(-5);

	l1.pop_front();
	l1.pop_front();

	//迭代器逆向循环
	list<int>::reverse_iterator it = l1.rbegin();
	while (it != l1.rend())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	print(l1);
}
void print(const list<int>& l1)
{
	//const类型的迭代器
	list<int>::const_iterator it = l1.cbegin();
	while (it != l1.cend())
	{
		//*it += 1;
		cout << *it << " ";
		it++;
	}
}

        注意const类型的对象遍历需要const类型的迭代器,如上。

        范围for是靠迭代器支持的,所以支持迭代器就支持范围for(c++11语法)。

        begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动

        rbegin和rend为反向迭代器。对迭代器执行++操作,迭代器向前移动 

3.插入删除

list接口说明
push_back在list的尾部插入一个值为val的元素
pop_back删除list尾部的元素
push_front在list的第一个元素之前插入值为val的元素
pop_back删除list的第一个元素
insert任意位置的插入
erase任意合法位置的删除
swap交换两个list中的元素
clear清空list中的有效元素

        例如:

void testList2()
{
	list<int> l1;
	//头插头删
    //尾删尾插
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);
	l1.push_back(5);

	l1.pop_back();
	l1.push_front(0);
	l1.push_front(-1);
	l1.push_front(-2);
	l1.push_front(-3);
	l1.push_front(-4);
	l1.push_front(-5);

	l1.pop_front();
	l1.pop_front();

	//迭代器逆向循环
	list<int>::reverse_iterator it = l1.rbegin();
	while (it != l1.rend())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	
}
void testList3()
{
	//
	list<int> l1;
	
	l1.insert(l1.begin(), 1);//调用insert头插 
	l1.insert(l1.begin(), 2);
	l1.insert(l1.begin(), 3); 
	l1.insert(l1.begin(), 4);
	l1.insert(l1.begin(), 5); 
	l1.insert(l1.begin(), 6);
	for (auto& e : l1)
	{
		cout << e << "->";
	}
	cout << endl;
	l1.insert(l1.end(), 10);//用insert尾插
	l1.insert(l1.end(), 20);
	l1.insert(l1.end(), 30);
	l1.insert(l1.end(), 40);

	l1.erase(--l1.end());//调用erase尾删
	for (auto& e : l1)
	{
		cout << e << "->";
	}
	cout << endl;
	list<int>l2(6, -2);//构造6个2
	cout << "l2交换前:" << endl;
	for (auto& e : l2)
	{
		cout << e << "->";
	}
	cout << endl;
	swap(l1, l2);//交换l1和l2
	cout << "l2交换后:" << endl;
	for (auto& e : l2)
	{
		cout << e << "->";
	}
	cout << endl;
	l2.clear();//清空l2
	for (auto& e : l2)
	{
		cout << e << "->";
	}
	cout << endl;
}

        注意list是不支持随机访问的,所以在调用erase和insert,迭代器不能加一个常数传给erase和insert ,如:

    list<int> l1;
	
	l1.insert(l1.begin(), 1);//调用insert头插 
	l1.insert(l1.begin(), 2);
	l1.insert(l1.begin(), 3); 
	l1.insert(l1.begin(), 4);
	l1.insert(l1.begin(), 5); 
	l1.insert(l1.begin(), 6);
    //下面这两个是错误的用法
    l1.insert(l1.end()+5, 40);

    l1.erase(l1.end()-3);//调用erase尾删

        insert的函数原型:

使用它要给它一个迭代器,不管是插入一个val还是n个val。

        erase的函数原型: 

给它的如果是一个迭代器删除的就是这个迭代器位置的val,如果是一段迭代器区间删除的就是这段迭代器区间的val。注意不能传end() 给它,程序会奔溃,因为end()迭代器实际上是头结点,在list对象生命周期没有结束的时候头结点是不可以被删除的,不然如果后面再去操作这个链表就会有内存访问冲突的问题。

4.容量相关

        4.1容量相关

函数说明接口说明
empty判断链表是否为空如果为空返回true,反之返回false
size返回list中有效节点的个数

 

void testList4()
{
	//
	list<int> l1;

	l1.insert(l1.begin(), 1);//调用insert头插 
	l1.insert(l1.begin(), 2);
	l1.insert(l1.begin(), 3);
	l1.insert(l1.begin(), 4);
	l1.insert(l1.begin(), 5);
	l1.insert(l1.begin(), 6);
	for (auto& e : l1)
	{
		cout << e << "->";
	}
	cout << endl;
	cout << l1.size() << endl;
	while (!l1.empty())//删除链表表头元素的方式遍历链表元素
	{
		cout << l1.front() << "->";//取出表头元素
		l1.pop_front();//删除头节点
	}
	cout << endl;
}

        4.2取出表头表尾数据

         

front和back
函数声明接口说明
front返回list第一个节点中值的引用
back返回list最后一个节点中值的引用

         例如:

void testList5()
{
	//
	list<int> l1;

	l1.insert(l1.begin(), 1);//调用insert头插 
	l1.insert(l1.begin(), 2);
	l1.insert(l1.begin(), 3);
	l1.insert(l1.begin(), 4);
	l1.insert(l1.begin(), 5);
	l1.insert(l1.begin(), 6);
	cout << l1.front() << endl;//输出链表第一个节点的值
	cout << l1.back() << endl;//输出链表最后一个节点的值
}

5.list的迭代器失效

        当我们在迭代器的某个位置插入一个元素迭代器会失效吗?请和我一起看看下面的代码!

void testList5()
{
	list<int> l1;
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);
	l1.push_back(5);
	l1.push_back(6);
	l1.push_back(7);
	list<int>::iterator it = l1.begin();
	it++;//到下一个节点的迭代器
	l1.insert(it, -4);//在这个迭代器这里插入一个val值迭代器会失效
    l1.insert(it, -5);//在这里继续插入一个val值程序会奔溃吗?
}

         实际上在list中插入元素迭代器是不会失效的。这与list的物理结构有关,因为插入一个节点,原来的节点是没有删除的,只是申请了一个新的节点然后与原来的节点建立联系,插入数据。

        如果删除一个元素呢?我们来试试

void testList7()
{
	list<int> l1;
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);
	l1.push_back(5);
	l1.push_back(6);
	l1.push_back(7);
	list<int>::iterator it = l1.begin();
	l1.erase(it);//删除节点的元素
	l1.insert(it,-4);
}

如果删除了这个节点,那么再对这个节点的迭代器进行操作程序就会报错,实际上这块内存已经被delete了,所以已经返还给操作系统了再进行其他操作就是不被允许的了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值