【C++】STL——list介绍及使用

news2024/11/17 10:44:10

🚀 作者简介:一名在后端领域学习,并渴望能够学有所成的追梦人。
🚁 个人主页:不 良
🔥 系列专栏:🛸C++  🛹Linux
📕 学习格言:博观而约取,厚积而薄发
🌹 欢迎进来的小伙伴,如果小伙伴们在学习的过程中,发现有需要纠正的地方,烦请指正,希望能够与诸君一同成长! 🌹


文章目录

  • 认识list
  • list的构造
  • 容量操作
    • empty函数
    • size函数
    • resize函数
  • 插入和删除操作
    • push_back和pop_back
    • push_front和pop_front
    • insert函数
    • erase函数
    • swap函数
    • clear函数
  • 迭代器
    • begin和end函数
    • rbegin和rend函数
  • 元素获取
    • front函数
    • back函数
  • 操作函数
    • sort函数
    • remove函数
    • remove_if函数
    • unique函数
    • reverse函数
    • assign函数
    • splice函数

认识list

  • list是一种可以在常数时间复杂度O(1)内对任意位置进行插入删除的序列式容器,并且该容器可以前后双向迭代。
  • list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立结点当中,在结点中通过指针指向其前一个元素和后一个元素。
  • list与forward_list非常相似,最主要的不同在于forward_list是单链表,只能进行单方向迭代。
  • 与其他容器相比,list通常在任意位置进行插入、删除元素的执行效率更高。
  • list和forward_list最大的缺陷是不支持在任意位置的随机访问,其次,list还需要一些额外的空间,以保存每个结点之间的关联信息(对于存储的类型较小元素来说这可能是一个重要的因素)。

list的构造

构造函数( (constructor))接口说明
list (size_type n, const value_type& val = value_type())构造的list中包含n个值为val的元素
list()构造空的list
list (const list& x)拷贝构造函数
list (InputIterator first, InputIterator last)用[first, last)区间中的元素构造list

使用:

#include <iostream>
#include <list>
#include <vector>
using namespace std;
int main()
{
	//构造空的list
	list<int> l1;
	for (auto e : l1)
	{
		cout << e << " ";
	}

	//构造含有5个值为6的int类型
	list<int> l2(5,6);
	for (auto e : l2)
	{
		cout << e << " ";
	}
	cout << endl;
	//6 6 6 6 6 

	vector<int> v1(3, 4);
	//list<int> l3(v1.begin(),v1.end());
	list<int> l3(l2.begin(), l2.end());
	for (auto e : l3)
	{
		cout << e << " ";
	}
	//6 6 6 6 6 
	cout << endl;

	//拷贝构造函数
	list<int> l4(l2);
	for (auto e : l3)
	{
		cout << e << " ";
	}
	//6 6 6 6 6 
	return 0;
}

容量操作

函数声明接口说明
empty检测list是否为空,是返回true,否则返回false
size返回list中有效节点的个数
resize扩容并且初始化

empty函数

检测list是否为空,如果是返回true,不是返回false。

#include <iostream>
#include <list>
using namespace std;
int main()
{
	list<int> l1;
	cout << l1.empty() << endl;//1
}

size函数

返回list中有效节点的个数。

#include <iostream>
#include <list>
using namespace std;
int main()
{
	list<int> l1(5,3);
	cout << l1.size() << endl;//5
}

resize函数

扩容并且初始化。

resize函数和之前的string类和vector类函数的resize函数规则差不多:

  • 当所给值大于当前的size时,将size扩大到该值,并且将扩大的数据初始化为第二个参数所给值,若未给出,则默认为容器所存储类型的默认构造函数所构造出来的值;

  • 当所给值小于当前的size时,将size缩小到该值。

#include <iostream>
#include <list>
using namespace std;

int main()
{
	list<int> l1(2, 6);
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl; //6 6
	l1.resize(4, 8); //将size扩大到4并且将扩大的值初始化为8
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl; //6 6 8 8
	l1.resize(2); //将size缩到2
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl; //6 6
	return 0;
}

插入和删除操作

函数声明接口说明
push_back尾插
push_front头插
pop_front头删
pop_back尾删
insert在指定的迭代器位置或区间插入数据
erase删除指定迭代器位置或迭代器区间的数据
swap交换两个list中的元素
clear清除list中的所有元素

push_back和pop_back

push_back是尾插,pop_back尾删。

使用:

下面的代码功能是依次在list尾部插入数据 1 2 3 4 5 6 7,插入完成之后打印;

打印之后再从尾部删除数据7 和 6:

#include <iostream>
#include <list>
using namespace std;
int main()
{
	list<int> l1;
	for (int i = 1; i < 8; i++)
	{
		l1.push_back(i);
	}
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
	//1 2 3 4 5 6 7
	l1.pop_back();
	l1.pop_back();
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
	//1 2 3 4 5
}

push_front和pop_front

头插和头删。

使用:

#include <iostream>
#include <list>
using namespace std;
int main()
{
    list<int> l1;
    for (int i = 1; i < 8; i++)
    {
        l1.push_front(i);
    }
    for (auto e : l1)
    {
        cout << e << " ";
    }
    cout << endl;
    //7 6 5 4 3 2 1 
    l1.pop_front();
    l1.pop_front();
    for (auto e : l1)
    {
        cout << e << " ";
    }
    cout << endl;
    // 5 4 3 2 1 
}

insert函数

//在指定的迭代器位置插入数据
iterator insert (iterator position, const value_type& val);
//在指定的迭代器位置插入n个val值
void insert (iterator position, size_type n, const value_type& val);
//在指定迭代器位置插入一段迭代器区间(左闭右开)
template <class InputIterator>
    void insert (iterator position, InputIterator first, InputIterator last);

在指定的迭代器位置插入数据

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

使用:

#include <iostream>
#include <list>
using namespace std;
int main()
{
    list<int> l1;
    l1.push_back(0);
    auto it = l1.begin();
    l1.insert(it, 100);//在头部插入值100
    for (auto e : l1)
    {
        cout << e << " ";
    }
    cout << endl;
    //输出100 0
}

在指定的迭代器位置插入n个val值

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

使用:

#include <iostream>
#include <list>
using namespace std;
int main()
{
	list<int> l1;
	l1.push_back(0);
	auto it = l1.begin();
	l1.insert(it,3, 100);//在头部插入3个值为100的数据
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
	//输出100 100 100 0
}

在指定迭代器位置插入一段迭代器区间

凡是和迭代器相关的基本上都是左闭右开。

#include <iostream>
#include <list>
using namespace std;
int main()
{
	list<int> l1;
	list<int> l2(4, 5);
	auto it = l1.begin();
	l1.insert(it,l2.begin(),l2.end());//在头部插入l2的begin到end的数据,左闭右开
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
	//输出5 5 5 5
}

erase函数

//删除指定迭代器位置的值
iterator erase (iterator position);
//删除指定迭代器区间的值
iterator erase (iterator first, iterator last);

使用:

#include <iostream>
#include <list>
using namespace std;
int main()
{	
	list<int> l1;
	for (int i = 1; i < 8; i++)
	{
		l1.push_front(i);
	}
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
	//输出7 6 5 4 3 2 1 
	// 删除指定迭代器位置
	//删除数据5
	auto it = find(l1.begin(), l1.end(), 5);//使用find函数查找
	l1.erase(it);
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
	//输出7 6 4 3 2 1

	//删除指定迭代器区间
	//删除从6到2之间的数据,左闭右开,所以要找到指向数据1的迭代器
	auto it1 = find(l1.begin(), l1.end(), 6);
	auto it2 = find(l1.begin(), l1.end(), 1);
	l1.erase(it1,it2);
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
	//输出7 1
}

前面说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响

所以erase()函数执行后,所指向的节点已被删除,迭代器失效,所以在下一次使用时,必须先给其赋值。

swap函数

交换两个list中的元素

void swap (list& x);

使用:

#include <iostream>
#include <list>
using namespace std;
int main()
{
	list<int> l1(2,6);
	list<int> l2(4, 5);
	//遍历l1
	for (auto e : l1)
	{
		cout << e << " ";
	}
	//输出6 6
	cout << endl;
	//遍历l2
	for (auto e : l2)
	{
		cout << e << " ";
	}
	//输出5 5 5 5 
	cout << endl;
    
	l1.swap(l2);//交换l1和l2
    
    //遍历l1
	for (auto e : l1)
	{
		cout << e << " ";
	}
	//输出5 5 5 5 
	cout << endl;
	//遍历l2
	for (auto e : l2)
	{
		cout << e << " ";
	}
	//输出6 6
	cout << endl;
}

clear函数

清除list中的所有元素

void clear();

使用:

#include <iostream>
#include <list>
using namespace std;
int main()
{
	list<int> l1(2,6);
	//遍历l1
	for (auto e : l1)
	{
		cout << e << " ";
	}
	//输出6 6
	l1.clear();//清除l1中元素

	for (auto e : l1)
	{
		cout << e << " ";
	}
	//什么也不输出
}

迭代器

我们可以将迭代器理解成指针,指向list中的某个节点。

函数声明接口说明
begin + end返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器
rbegin + rend返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置的 reverse_iterator,即begin位置

迭代器都是左闭右开

begin和end函数

使用:

#include <iostream>
#include <list>
#include <vector>
using namespace std;
int main()
{
    list<int> l1;
    for (int i = 0; i < 5; i++)
    {
        l1.push_back(i);
    }
    //正向迭代器的使用
    //正向遍历
    list<int>::iterator it = l1.begin();
    while (it != l1.end())//遍历
    {
        cout << *it << " ";
        it++;
    }
    //输出 0 1 2 3 4
    cout << endl;
}

rbegin和rend函数

#include <iostream>
#include <list>
#include <vector>
using namespace std;
int main()
{
    list<int> l1;
    for (int i = 0; i < 5; i++)
    {
        l1.push_back(i);
    }
	//反向迭代器的使用
    //反向遍历
    list<int>::reverse_iterator rit = l1.rbegin();
    while (rit != l1.rend())
    {
        cout << *rit << " ";
        rit++;
    }
    //输出 4 3 2 1 0
    cout << endl;
}

元素获取

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

front函数

front函数用于获取list容器当中的第一个元素的引用(能够修改元素)。

使用:

#include <iostream>
#include <list>
using namespace std;
int main()
{
	list<int> l1(2,6);
	//遍历l1
	for (auto e : l1)
	{
		cout << e << " ";
	}
	//输出6 6
    cout << l1.front() << endl;//获取第一个元素,输出6
	l1.front() = 100; //获取第一个元素并将第一个元素改为100

	for (auto e : l1)
	{
		cout << e << " ";
	}
	//输出100 6
}

back函数

back函数用于获取list容器当中的最后一个元素(能够修改元素)。

使用:

#include <iostream>
#include <list>
using namespace std;
int main()
{
	list<int> l1(2,6);
	//遍历l1
	for (auto e : l1)
	{
		cout << e << " ";
	}
	//输出6 6
	cout << l1.back() << endl;//获取最后一个元素,输出6
	l1.back() = 100; //获取最后一个元素并将其改为100

	for (auto e : l1)
	{
		cout << e << " ";
	}
	//输出 6 100
}

操作函数

函数声明接口说明
sort将容器当中的数据默认排为升序
remove删除容器中指定值的元素
remove_if删除容器中满足条件的元素
unique删除容器当中连续的重复元素
reverse将容器当中元素的位置进行翻转逆置
assign新内容分配给容器替换容器当前内容
splice两个list容器之间的拼接

sort函数

算法库中的sort函数代码如下:是通过指针相减算出来的,而list容器不是连续的地址所以这种算法对于list来说并不适用。

image-20230701160438900

list容器中的sort函数使用的是归并排序,算法库中的sort使用的是快排,快排是三个数取中间数同样不适用list。

从功能上来说迭代器要分三类:

1.单向迭代器 ++

2.双向迭代器(list) ++ –

3.随机迭代器(vector string) ++ – + -

在函数使用的时候如果模板中是双向不能使用单向,如果是单向可以传随机和双向。

算法库中的sort函数迭代器要传随机迭代器:

image-20230701160750349

sort函数使用:

#include <iostream>
#include <list>
using namespace std;
int main()
{
	list<int> l1;
	//遍历l1
	for (int i = 13; i >= 3; i--)
	{
		l1.push_back(i);
	}
	//输出6 6

	for (auto e : l1)
	{
		cout << e << " ";
	}
	//输出13 12 11 10 9 8 7 6 5 4 3
	l1.sort();
	for (auto e : l1)
	{
		cout << e << " ";
	}
	//输出 3 4 5 6 7 8 9 10 11 12 13
}

但是在实际中我们很少使用list的sort排序,因为性能不行。

比较vector和list容器的sort排序时间:

#include <iostream>
#include <algorithm>
#include <vector>
#include <list>
using namespace std;
int main()
{

	//list和vector的sort函数性能测试
	srand(time(nullptr));
	list<int> l1;
	vector<int> v1;
	const int N = 1000000;

	v1.reserve(N);
	for (int i = 0; i < N; i++)
	{
		auto e = rand();//随机数
		v1.push_back(e);//插入
		l1.push_back(e);//插入
	}
	int begin1 = clock();
	sort(v1.begin(), v1.end());
	int end1 = clock();
	int begin2 = clock();
	l1.sort();
	int end2 = clock();
	cout << "vector sort:" << (end1 - begin1) << endl;//vector排序时间
	cout << "list sort:" <<  (end2 - begin2) << endl;//list排序时间

在release下进行测试:

image-20230701162113993

我们再尝试先将list容器中的数据放在vector中,然后再排序,排完序之后再放到list容器中:

#include <iostream>
#include <algorithm>
#include <vector>
#include <list>
using namespace std;
int main()
{

	//list和vector的sort函数性能测试
	srand(time(nullptr));
	list<int> l1;
	vector<int> v1;
	const int N = 1000000;

	v1.reserve(N);
	for (int i = 0; i < N; i++)
	{
		auto e = rand();//随机数
		v1.push_back(e);//插入
		l1.push_back(e);//插入
	}
	//vector排序时间
	int begin1 = clock();
	sort(v1.begin(), v1.end());
	int end1 = clock();


	int begin2 = clock();
	//将l1中的数据放在vector中排序
	vector<int> v2;
	v2.reserve(N);
	for (auto e : l1)
	{
		v2.push_back(e);
	}
	//排序
	sort(v2.begin(), v2.end());
	//排序之后再将其放到list中
	for (auto e : v2)
	{
		l1.push_back(e);
	}
	int end2 = clock();
	cout << "vector sort:" << (end1 - begin1) << endl;//vector排序时间
	cout << "list sort:" <<  (end2 - begin2) << endl;//list排序时间
}

运行结果:

image-20230701162552465

通过两个结果比较,可见即便是将list放到vector中再排序再放回list中都要比list中的sort函数直接排序要快。

remove函数

删除容器中指定值的元素。

void remove (const value_type& val);

使用:

#include <iostream>
#include <list>
using namespace std;
int main()
{
	list<int> l1;
	for (int i = 1; i < 8; i++)
	{
		l1.push_front(i);
	}
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
	//输出7 6 5 4 3 2 1 
	l1.remove(6);
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
	//输出7 5 4 3 2 1 
}

remove_if函数

remove_if函数用于删除容器当中满足条件的元素。

template <class Predicate>//函数模板
  void remove_if (Predicate pred);

使用:

#include <iostream>
#include <list>
using namespace std;

bool single_digit(const int& val)
{
	return val > 4;
}
int main()
{
	
	list<int> l1;
	for (int i = 1; i < 8; i++)
	{
		l1.push_front(i);
	}
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
	//输出7 6 5 4 3 2 1 
	lt.remove_if(single_digit); //删除容器当中值大于4的元素
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl; //10 18
	return 0;
}

unique函数

删除容器当中连续的重复元素。

删除连续的重复元素并不能做到去重的效果,如果要做到去重就要提前排好序,否则的话只能保证两个相邻的元素不重复。

#include <iostream>
#include <list>
using namespace std;
int main()
{

	list<int> l1;
	for (int i = 1; i < 8; i++)
	{
		l1.push_back(i);
		if (i % 2 == 0) {
			l1.push_back(i);
		}
	}
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
	//输出1 2 2 3 4 4 5 6 6 7
	l1.push_back(6);//尾插6
	l1.unique();//去除连续的重复数据
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
	//输出1 2 3 4 5 6 7 6
}

reverse函数

将容器当中元素的位置进行翻转逆置。

void reverse();

使用:

#include <iostream>
#include <list>
using namespace std;
int main()
{

	list<int> l1;
	for (int i = 1; i < 8; i++)
	{
		l1.push_back(i);
	}
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
	//输出1 2 3 4 5 6 7
	l1.reverse();//翻转逆置
	for (auto e : l1)
	{
		cout << e << " ";
	}
	//输出7 6 5 4 3 2 1
	cout << endl;
}

assign函数

将新内容分配给容器替换容器当前内容,assign有两种方式:

1.将所给迭代器区间当中的内容分配给容器。

2.将n个值为val的数据分配给容器。

//将所给迭代器区间当中的内容分配给容器
template <class InputIterator>
  void assign (InputIterator first, InputIterator last);
//将n个值为val的数据分配给容器
void assign (size_type n, const value_type& val);

使用:

#include <iostream>
#include <list>
using namespace std;
int main()
{
	list<int> l1;
	list<int> l2(12, 8);
	for (int i = 1; i < 8; i++)
	{
		l1.push_back(i);
	}
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
	//输出1 2 3 4 5 6 7
	//将n个值为val的数据分配给容器替换当前内容
	l1.assign(5, 6);
	for (auto e : l1)
	{
		cout << e << " ";
	}
	//输出6 6 6 6 6
	cout << endl;

	//将所给迭代器区间当中的内容分配给容器
	l1.assign(l2.begin(), l2.end());
	for (auto e : l1)
	{
		cout << e << " ";
	}
	//输出8 8 8 8 8 8 8 8 8 8 8 8
	cout << endl;
}

splice函数

splice函数用于两个list容器之间的拼接,三种拼接方式:

//将整个容器拼接到另一个容器的指定迭代器位置
void splice (iterator position, list& x);
//将容器当中的某一个数据拼接到另一个容器的指定迭代器位置
void splice (iterator position, list& x, iterator i);
//将容器指定迭代器区间的数据拼接到另一个容器的指定迭代器位置
void splice (iterator position, list& x, iterator first, iterator last);

容器当中的数据被拼接到另一个容器之后在之前的容器中就不存在了。

使用:

#include <iostream>
#include <list>
using namespace std;
int main()
{
	list<int> l1(2, 6);
	list<int> l2(2, 8);
	l1.splice(l1.begin(), l2); //将容器lt2拼接到容器lt1的开头
	for (auto e : l1)
	{
		cout << e << " ";
	}
	cout << endl; //8 8 6 6

	list<int> l3(2, 6);
	list<int> l4(2, 8);
	l3.splice(l3.begin(), l4, l4.begin()); //将容器lt4的第一个数据拼接到容器lt3的开头
	for (auto e : l3)
	{
		cout << e << " ";
	}
	cout << endl; //8 6 6

	list<int> l5(4, 8);
	list<int> l6(4, 6);
	l5.splice(l5.begin(), l6, l6.begin(), l6.end()); //将容器lt6的指定迭代器区间内的数据拼接到容器lt5的开头
	for (auto e : l5)
	{
		cout << e << " ";
	}
	cout << endl; //6 6 6 6 8 8 8 8
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/727407.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安装Anaconda

一、Anaconda简介 Anaconda&#xff0c;一个开源的Python发行版本&#xff0c;可用于管理Python及其相关包&#xff0c;包含了conda、Python等180多个科学包及其依赖项。当我们需要不同的Pytorch版本的时候&#xff0c;不需要卸载重新安装&#xff0c;可以通过Anaconda创建不同…

短视频抖音账号矩阵系统源码---功能架构示例1

一、短视频账号矩阵系统源码开发服务器集群化处理开发成本更低&#xff08;前提&#xff09; 什么是集群化处理视频内存内耗&#xff1f;集群化处理视频内存内耗是指通过建立集群系统&#xff0c;将视频处理任务分配给多个计算节点进行并行处理&#xff0c;以减少单个计算节点…

氨基酸中间体35309-53-6,cyclo(Asp-Asp),CYCLO(-天冬氨酸-ASP)

&#xff08;文章资料汇总来源于&#xff1a;陕西新研博美生物科技有限公司小编MISSwu&#xff09;​ 试剂基团反应特点&#xff08;Reagent group reaction characteristics&#xff09;&#xff1a; cyclo(Asp-Asp)&#xff0c;35309-53-6&#xff0c;一种氨基酸中间体&…

平衡搜索二叉树——AVL树

AVL树 1. AVL树的概念2. AVL树节点的定义3. AVL树的插入思路4. AVL树的平衡调整思路平衡因子更新思路LL型——右单旋RR型——左单旋LR型——左右旋RL型——右左旋 5. AVL树插入判断平衡调整类型6. AVL树插入的代码实现7. AVL树总结8. AVL树的验证9. AVL树的性能 1. AVL树的概念…

600多个人工智能AI工具汇总(AIGC时代-超级个体的崛起),免费提供和介绍(第一讲)

这里是600多个人工智能AI工具汇总第一讲&#xff0c;每天介绍5个&#xff0c;主要是我写不完教程了&#xff0c;你懂的&#xff0c;视频最后会告诉大家获取方式的。现在请大家同我一起进入AIGC的世界。 第一个&#xff1a;《AIGC时代&#xff1a;超级个体的崛起》用来介绍AIGC…

【AI绘画】用魔法打败魔法,用ChatGPT生成绘画

随着人工智能技术的不断发展&#xff0c;我们可以利用ChatAI这款大语言模型来辅助我们在绘画过程中获得更多创意和灵感。 一、了解AI绘画功能 它可以快速、自动、准确地从大量原始数据中生成新内容&#xff0c;大大提高了内容创作效率&#xff0c;AI绘画使用机器学习算法&…

金色传说:SAP-MM-ME51N/ME52N采购申请增强

文章目录 业务场景一、增强方式:BADI二、增强步骤1.SE18/SE19创建增强实施2.增强代码3.实现效果总结业务场景 在企业中,通常需要控制采购业务中的特殊权限,本次遇到的业务场景:公司启用了SAP的 PPDS模块, 因此,需要控制业务员不能手动使用ME51N创建采购申请.因为标准的权限对象…

LNMP架构及应用部署(搭建电影网站)

目录 一、安装nginx 1、关闭防火墙和selinux 2、安装依赖软件 3、创建管理nginx用户 4、解压源码包 5、安装nginx 6、优化nginx命令 7、检测配置文件是否有错误 8、启动nginx 9、编辑nginx脚本&#xff08;可根据自己需求编辑&#xff09; 二、安装mysql数据库 1、先查看有没有…

Java安全——数字签名

Java安全 数字签名 签名类 签名的jar文件可以通过Java的jarsigner工具进行管理。jarsigner工具使用密钥库中的信息来查找特定的实体&#xff0c;并使用这些信息对jar文件进行签名或验证签名。 要创建签名的jar文件&#xff0c;我们可以使用以下命令&#xff1a; jarsigner…

游戏引擎的cpu/gpu粒子系统设计思想

开篇 网上有很多篇粒子系统源码解析&#xff0c;但是只是简单的接口罗列&#xff0c;没有从最原理出发去讲清楚粒子系统的来龙去脉&#xff0c;我将从粒子系统的本质去讲清楚它的设计理念&#xff0c;当理解了它的理念以后&#xff0c;很多粒子遇到的问题就会迎刃解决了&#…

常用的 Vs Code插件

推荐下自己在使用的 vs code 插件 1. Vue VSCode Snippets / Vue 3 Snippets 功能&#xff1a; 提供vue 相关代码块 2. Git History 功能&#xff1a;查看文件git提交历史 用法&#xff1a;右键你想要查看的文件&#xff0c;选 Git:Open File History 3. GitLens — Git …

LVS+Keepalived架构(负载均衡高可用集群)

一、高可用简介 普通的群集的部署是通过一台调度器控制调配多台节点服务器进行业务请求的处理&#xff0c;但是仅仅是一台调度器&#xff0c;就会存在极大的单点故障风险&#xff0c;当该调度器的链路或则调度器本身出现故障时&#xff0c;就会导致整个业务的无法正常进行 而高…

超越传统标注方法:doccano平台提供智能化数据标注解决方案

目录 前言一、doccano的介绍、安装1-1、doccano的介绍1-2、doccano的安装、初始化配置 二、序列标注任务2-1、登录2-2、创建任务2-3、数据上传2-4、添加标签2-5、任务标注2-6、数据导出 总结 前言 Doccano是一种用于文本标注的开源工具&#xff0c;旨在简化和加速标注任务的进行…

RocketMQ5.0--定时消息

RocketMQ5.0–定时消息 一、定时消息概览 定时消息或延迟消息是指消息发送到Broker后&#xff0c;并不立即被消费而是要等到特定的时间后才能被消费。RocketMQ并不支持任意的时间精度延迟&#xff0c;只支持特定延迟时间的延迟消息。 消息延迟级别在Broker端通过MessageStore…

vue中控制element表格列的显示与隐藏

背景 根据‘执行进度计算方式’的单选框里面的选项不同&#xff0c;展示不同的column 按最小制剂单位统计: 按含量统计: 实现方式 就是拿到选项框里面的值&#xff0c;再根据里面的值来判断哪些column显示和隐藏&#xff1b;关于显示和隐藏可以设置变量&#xff1b; <…

SpringBoot原理分析 | Spring Data整合:JDBC、Druid、Mybatis

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; Spring Data Spring Data是一个用于简化数据库访问和操作的开源框架&#xff0c;为开发人员提供了一种通用的方式来处理不同类型的数据存储&#xff0c;例如关系型数据…

android13(T) Settings 主页面 Suggestion 菜单源码分析

1、什么是 Suggestion 菜单 呐&#xff0c;下面这个就是 Suggestion 菜单&#xff0c;一般出现在设置主界面最上方位置。 出现时机需要满足三个条件&#xff0c;1、设备不是 LowRam 设备 2、启用 settings_contextual_home 特性 3、在开机一定时间后(一般是几天&#xff0c;具…

山西电力市场日前价格预测【2023-07-08】

日前价格预测 预测明日&#xff08;2023-07-08&#xff09;山西电力市场全天平均日前电价为341.87元/MWh。其中&#xff0c;最高日前电价为871.53元/MWh&#xff0c;预计出现在22: 15。最低日前电价为143.16元/MWh&#xff0c;预计出现在13: 30。以上预测仅供学习参考&#xff…

缓存设计(本地缓存 + 分布式缓存)

缓存设计 前言正文缓存对象缓存服务缓存策略本地缓存Guava的使用 分布式缓存Redis缓存分布式缓存的生命周期分布式缓存的一致性问题 源码解读从缓存中获取秒杀品 分布式锁 总结参考链接 前言 大家好&#xff0c;我是练习两年半的Java练习生&#xff0c;本篇文章会分析秒杀系统…

el-form实现其中一个填写即可的校验

<el-formref"form":model"formData":rules"formRules"label-width"130px"><el-row :gutter"24"><el-col :span"12"><el-form-item label"司机姓名 :" prop"driverName"…