list的使用

前言

我们前面已经对string和vector进行了学习使用,以及对他们的底层进行了模拟实现!本期我们继续学习STL的另外一个容器---list。

本期内容介绍

什么是list?

list的常用接口

什么是list?

还是来看看官方的文档说明!

这里通过官方文档我们可以知道!list是一个带头双向循环的链表!在插入和删除时,时间复杂度是常量级别的!

list常用接口

在正式的开始介绍接口使用前,我们还是来了解一下类型重命名!

这里主要用到的就是上面的三个! value_type 就是T, reference 是value_type&, size_type 就是size_t

构造、拷贝构造、赋值拷贝、析构

list<int> lt1;//空构造

list<int> lt2(10, 6);//n 个 val构造

vector<int> v = { 1, 2,4,56,7,8,-1 };

list<int> lt3(v.begin(), v.end());//迭代器区间构造

list<int> lt4(lt2);//拷贝构造

这里除了介绍这些常见的外!这里在穿插一个C++11引入的一个非常好用的,初始化序列初始化!

这个在上期vector的模拟实现已经介绍了,auto ret = {1,2,3};此时的ret就是initializer_list<int>。

list<int> lt5 = { 1,2,3,4,5 };//C++11的初始化序列初始化

list<int> lt4(lt2);//拷贝构造

list<int> lt5 = { 1,2,3,4,5 };//C++11的初始化序列初始化

lt5 = lt4;//赋值拷贝

析构还是一样的:清理资源、释放空间~!

迭代器

正向

list<int> lt = { 1,2,3,4,5 };//C++11的初始化序列初始化
const list<int> clt = { 10, 20,30, 40 };

list<int>::iterator it = lt.begin();//正向
while (it != lt.end())
{
	cout << *it << " ";
	++it;
}
cout << endl;

list<int>::const_iterator cit = clt.begin();//const正向
while (cit != clt.end())
{
	cout << *cit << " ";
	++cit;
}
cout << endl;

支持迭代器必然支持范围for,范围for就是傻傻的替换迭代器!

反向

list<int>::reverse_iterator it = lt.rbegin();//反向
while (it != lt.rend())
{
	cout << *it << " ";
	++it;
}
cout << endl;

list<int>::const_reverse_iterator cit = clt.rbegin();//const反向
while (cit != clt.rend())
{
	cout << *cit << " ";
	++cit;
}
cout << endl;

const和非const的区别主要还是权限的问题~!如果不修改建议使用const的!!!

注意:这里的迭代器需要指定类域的原因是模板的原因,模板参数不一样就是一个类,为了让迭代器用法统且不冲突,需要指定是哪个类的迭代器~!

容量

empty

list<int> lt = { 1,2,3,4,5,6,7,8,9 };
bool ret = lt.empty();
cout << ret << endl;

size

list<int> lt = { 1,2,3,4,5,6,7,8,9 };
size_t sz = lt.size();
cout << sz << endl;

元素访问

这里文档上说的很清楚:如果是空链表的话,你去取头和尾的数据是未定义的行为!!因为当链表为空时,头尾就是哨兵位的头结点,我们只是规定头结点的next指向实际链表的第一个节点,_prev指向对后一个元素,并未规定头结点的数据域存的是啥,所以如果为空链表,你去取就是未定义行为!

这和begin迭代器不一样,迭代器是返回链表的元素,这里是返回引用!

list<int> lt = { 1,2,3,4,5,6,7,8,9 };
int front = lt.front();
int back = lt.back();

cout << front << " " << back << endl;

const list<int> clt = { 10, 20,30, 40 };
int cfront = clt.front();
int cback = clt.back();

cout << cfront << " " << cback << endl;

修改

删除的这三个是涉及右值引用!在后面的C++11那一期会专门介绍~!

assign

list<int> lt = { 1,2,3,4,5,6,7,8,9,10 };
list<int> lt2;
list<int> lt3 = { 0, 2,4,6,8 };
lt.assign(5, 1);
for (auto& e : lt)
{
	cout << e << " ";
}
cout << endl;

lt2.assign(++lt3.begin(), --lt3.end());
for (auto& e : lt2)
{
	cout << e << " ";
}
cout << endl;

这个和构造函数那里很像,但是不一样!这个是已经存的你再去把他的原来内容用指定的内容替换掉!

push_front

list<int> lt = { 1,2,3,4 };
lt.push_front(0);
for (auto& e : lt)
{
	cout << e << " ";
}
cout << endl;

pop_front

list<int> lt = { 1,2,3,4 };

lt.pop_front();
for (auto& e : lt)
{
	cout << e << " ";
}
cout << endl;

push_back

list<int> lt = { 1,2,3,4 };

lt.push_back(-5);
for (auto& e : lt)
{
	cout << e << " ";
}
cout << endl;

pop_back

list<int> lt = { 1,2,3,4 };

lt.pop_back();
for (auto& e : lt)
{
	cout << e << " ";
}
cout << endl;

insert

list<int> lt = { 1,2,3,4 };
lt.insert(lt.begin(), 0);//在pos位置插入一个val

lt.insert(++lt.begin(), 5, -1);//在pos位置插入n个val

vector<int> v = { 90, 98, 23,34,56 };
lt.insert(lt.begin(), v.begin(), v.end());//在pos位置插入一个迭代器区间

erase

list<int> lt = { 1,2,3,4 };
lt.erase(lt.begin());//删除pos位置的元素

lt.erase(++lt.begin(), lt.end());//删除一段迭代器区间

resize

由于是链表,所以不用考虑扩容的问题!这里的resize就要变成了尾插和尾插了!

list<int> lt = { 1,2,3,4 };

lt.resize(3);//相当于尾删,只保留前n个元素

lt.resize(10, 0);//相当于尾插到节点数目为10,不够的就是0

swap

还是和前面的两个容器的一样,他这里的是对list对象的属性进行交换!

list<int> lt1 = { 1,2,3,4 };
list<int> lt2 = { 10,20,30,40 };

lt1.swap(lt2);

clear

list<int> lt = { 1,2,3,4 };

lt.clear();
cout << lt.size() << endl;

其他操作

splice

splice是粘结,结合的意思!这个接口的作用是转移链表的元素!重载了三个:

将一个链表的数据转移到另一个链表的pos位置

将一个链表的i位置的元素转移到另一个链表的pos位置

将一个链表的一个迭代器区间转移到另一个链表的pos位置

list<int> lt1 = { 1,2,3,4,5,6,7,8,9 };
list<int> lt2 = { 0, -1,-2 };

lt1.splice(lt1.begin(), lt2);//在pos位置,将x转移过来

lt2.splice(lt2.end(), lt1, ++lt1.begin());//在pos位置将x的i位置的一个元素转移过来

lt2.splice(++lt2.begin(), lt1, ++lt1.begin(), --lt1.end());//在pos位置将x的一段迭代器区间给转移过来

remove

这个函数的作用是:删除所有特定的值!

list<int> lt = { 2,3,2,2,2,4,5,6,1,2 };
lt.remove(2);
print(lt);

remove_if

这个函数的作用是删除符合条件的元素,这里的形参可以是一个对象,也可以是一个函数指针!

bool is_odd(const int& val)
{
	return val % 2 == 0;
}

struct single_digit
{
	bool operator() (const int& val)
	{
		return val < 10;
	}
};

void test_list7()
{
	list<int> lt = { 2,3,2,2,2,4,5,6,1,2,21,11,23 };

	lt.remove_if(is_odd);
	print(lt);

	lt.remove_if(single_digit());
	print(lt);
}

unique

一看名字就知道这是去重的,但是这个去重是去重连续相邻的重复元素

list<int> lt = { 2,3,2,2,2,2,4,5,6,1,2,21,11,23 };

lt.unique();
print(lt);

merge

这接口的作用就是:合并两个链表!但注意:这两个链表必须是有序的!!!!

list<int> lt1 = { 1,3,7,8,9 };
list<int> lt2 = { 2,4,5,7,9 };

lt1.merge(lt2);
print(lt1);
print(lt2);//此时lt2是空的

sort

这个接口的作用是:对链表进行排序!它的底层是归并排序!

list<int> lt = { 1,3,2,1,-1,7,8,9 };

lt.sort();
print(lt);

但是这个效率就很,,,不太好~!不是归并不行,是链表排序不太行!

OK,举个例子:

void test_op1()
{
	srand(time(0));
	const int N = 1000000;

	list<int> lt1;
	list<int> lt2;

	vector<int> v;

	for (int i = 0; i < N; ++i)
	{
		auto e = rand() + i;
		lt1.push_back(e);
		v.push_back(e);
	}

	int begin1 = clock();
	// 
	sort(v.begin(), v.end());
	int end1 = clock();

	int begin2 = clock();
	lt1.sort();
	int end2 = clock();

	printf("vector sort:%d\n", end1 - begin1);
	printf("list sort:%d\n", end2 - begin2);
}

这个代码是将同样的数据插入到一个vector和一个list,分别对他们排序,看他们排序花费的时间!

差了两倍多!!!再来看一个:

void test_op2()
{
	srand(time(0));
	const int N = 1000000;

	list<int> lt1;
	list<int> lt2;

	for (int i = 0; i < N; ++i)
	{
		auto e = rand();
		lt1.push_back(e);
		lt2.push_back(e);
	}

	int begin1 = clock();
	// vector

	vector<int> v(lt2.begin(), lt2.end());
	// 
	sort(v.begin(), v.end());

	// lt2
	lt2.assign(v.begin(), v.end());

	int end1 = clock();

	int begin2 = clock();
	lt1.sort();
	int end2 = clock();

	printf("list copy vector sort copy list sort:%d\n", end1 - begin1);
	printf("list sort:%d\n", end2 - begin2);
}

这个代码是:先将两个链表插入相同的数据,在将一个放到vector中排序,然后再拷回来,一个是直接调用链表的sort!

直接差了4倍!所以,list的这个sort效率真不咋地,建议少用~!

reverse

这个函数的作用就是反转链表!

list<int> lt = { 1,2,3,4,5,6,7,8 };
lt.reverse();
print(lt);

非成员函数swap

有这个接口的原因和前面的几个容器一样!防止调到标准库里面的那个!

list<int> lt1 = { 1,2,3};
list<int> lt2 = { 10,20,30, 50};

swap(lt1, lt2);
print(lt1);
print(lt2);

OK,本期内容就分享到这里,我们下期再见~!

结束语:不要因为别人的三言两语就打破你的深思熟虑!

  • 39
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: vant list 是一个基于 Vue 实现的列表组件,可以用于展示一组有序或无序的数据。 使用 vant list 可以简化列表数据的渲染和展示工作,提高开发效率。具体使用方法如下: 1. 在 vue 项目中安装 vant 组件库,可以使用 npm 或 yarn 进行安装。 2. 在需要使用 vant list 的组件中引入 vant 组件库,可以使用 import 或 require 语句。 3. 在需要展示列表的页面中,使用 vant list 组件,并通过 prop 属性传入要展示的数据。 4. 可以根据需要,通过设置 vant list 的属性来自定义列表的样式和布局,如显示方式、每行显示的列数等。 5. 根据列表的业务逻辑,可以为 vant list 组件的每一项绑定相应的点击事件或其他交互逻辑。 6. 如果列表数据是异步获取的,可以在组件的生命周期钩子函数中通过调用异步接口获取数据,并将获取到的数据赋值给 vant list 组件的数据属性。 7. 在 css 样式中可以自定义 vant list 的布局和样式,实现更好的视觉效果,也可以覆盖默认的样式。 vant list 是一个功能强大且易用的列表组件,可以帮助开发者高效地展示和管理列表数据。通过以上步骤的操作,可以轻松使用 vant list 实现列表数据的展示和交互。 ### 回答2: vant list是一个基于Vue.js的移动端组件库Vant提供的列表组件,用于展示和操作数据列表。 vant list提供了丰富的功能和样式,可以方便地实现各种列表的展示和操作需求。首先,我们需要安装vant库并导入vant list组件: ``` npm install vant import { List } from 'vant'; Vue.use(List); ``` vant list主要包含两个部分:列表项和列表项之间的分隔符。我们可以通过设置不同的属性来自定义vant list的样式和行为。 首先,我们可以使用v-model指令绑定数据到vant list组件中,从而实现数据的动态展示和操作。例如: ``` <van-list v-model="listData"> <van-cell v-for="(item, index) in listData" :key="index"> {{ item }} </van-cell> </van-list> ``` 上述示例中,v-model绑定了listData数组,vant list会根据数组的数据动态生成对应的列表项。 然后,我们可以使用vant list提供的属性来自定义列表的样式和行为。例如,使用`border`属性添加列表项之间的边框: ``` <van-list v-model="listData" border> <van-cell v-for="(item, index) in listData" :key="index"> {{ item }} </van-cell> </van-list> ``` 此外,vant list还提供了很多其他属性,例如`loading`用于显示加载状态、`error`用于显示错误状态等等,可以根据需求进行设置。 总之,vant list是一个方便易用的列表组件,通过简单的配置和绑定数据,我们可以实现移动端的列表展示和操作功能。在具体使用中,可以根据需求灵活地设置各种属性和样式,来满足不同的业务需求。 ### 回答3: vant list是Vant组件库中的一个列表组件,主要用于展示数据列表。使用vant list可以方便地创建一个具备滚动功能的列表页面。 vant list使用步骤如下: 1. 导入vant list组件:首先需要在项目中引入vant相关的样式文件和vant list组件。 2. 创建列表数据:定义一个数组,用于存放要展示的数据列表。 3. 使用vant list组件:在页面中使用vant list组件,并将列表数据绑定到组件的属性上。 4. 设置列表项模板:在vant list组件中定义列表项的模板。可以使用vant提供的内置样式,也可以自定义样式。 5. 绑定事件:如果需要对列表项进行操作,可以在模板中绑定相应的事件处理函数。 6. 生成列表:将列表数据传入vant list组件的属性中,即可生成对应的列表。 7. 添加滚动功能:vant list组件自带滚动功能,当列表数据过多时会自动展示滚动条。 8. 完善其他功能:根据需求完善列表的其他功能,比如下拉刷新、上拉加载更多等。 总结起来,vant list组件提供了简单易用的方法来展示数据列表,可以根据自己的需求定制列表项样式和操作逻辑。使用vant list可以快速创建一个功能齐全的列表页面,提升用户体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值