c++初阶-----STL---list

news2024/9/19 10:58:48

作者前言

🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂
​🎂 作者介绍: 🎂🎂
🎂 🎉🎉🎉🎉🎉🎉🎉 🎂
🎂作者id:老秦包你会, 🎂
简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂
喜欢学习C语言、C++和python等编程语言,是一位爱分享的博主,有兴趣的小可爱可以来互讨 🎂🎂🎂🎂🎂🎂🎂🎂
🎂个人主页::小小页面🎂
🎂gitee页面:秦大大🎂
🎂🎂🎂🎂🎂🎂🎂🎂
🎂 一个爱分享的小博主 欢迎小可爱们前来借鉴🎂


list

  • **作者前言**
  • list的介绍
  • list的简单使用
    • reverse
    • merge
    • unique
    • splice
  • list的模拟实现
    • 迭代器的模拟
      • **普通的迭代器**
      • const迭代器
      • 反向迭代器
      • 重载->

list的介绍

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

#include<iostream>
#include<vector>
#include<list>
using namespace std;
int main()
{
	list<int> lt;
	lt.push_back(10);
	lt.push_back(11);
	lt.push_back(12);
	lt.push_back(13);
	lt.push_back(14);
	lt.push_back(15);
	list<int>::iterator it = lt.begin();
	while (it != lt.end())
	{
		cout << *it;
		it++;
	}
	cout << endl;
	for (auto& e:lt)
	{
		cout << e;
	}
	return  0;
}

前面我们知道,string和vector的遍历方式有迭代器,下标和 地址
但是在list中没有下标,通过地址去访问困难,只能通过迭代器去访问,这个时候就会很方便,不用再和之前的C语言那样,获取到对应的地址进行方位,我们只需获取到对应的迭代器就可以快速,迭代器的优势也慢慢的体现出来了

list的简单使用

经过前面的string和vector我们可以使用一些简单 的成员函数,begin、end等相关的成员函数,我这里不详细的去介绍了,下面我简单的介绍一些不经常讲过的,

reverse

需要注意的是这个名称,在string和vector中是reserve()成员函数,是一个进行空间扩大的函数,这两者是不一样的,而reverse是list中特有的成员函数
进行翻转,把元素从头到尾进行翻转

	list<int> lt;
	lt.push_back(10);
	lt.push_back(11);
	lt.push_back(12);
	lt.push_back(13);
	lt.push_back(14);
	lt.push_back(15);
	list<int>::iterator it = lt.begin();
	while (it != lt.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	lt.reverse();
	for (auto& e:lt)
	{
		cout << e << " ";
	}

在这里插入图片描述

merge

合并列表
该算法将一个有序list容器加入另一个有序list容器中,且两个list容器必须都为逆序或顺序

unique

去重
前提条件就是: 相同的元素要站在一堆,最好的方式就是有序

splice

连接
把一个list容器的一些内容或者整个连接到另外一个list容器上面去,右边的list容器就变空了
在这里插入图片描述

list的模拟实现

前面我们实现过单链表和双向链表,这次我们模拟实现list和前面的类似
节点的类以及list的类,有两个
我们可以写一个命名空间里面进行
下面我们以这个图为例子
在这里插入图片描述
所以我们要创建一个节点类, list里面是一个链表,
节点类:

	//节点类
	template<class T>
	struct ListNode
	{
	public:
		ListNode<T>* left;
		ListNode<T>* rigth;
		T val;
	
		ListNode(const T& num = T())
			:left(nullptr)
			,rigth(nullptr)
			,val(num)
		{
	
		
		}
		bool operator==(const ListNode<T> n)
		{
			return this == &n;
		}
	};

跟我们刚开始 的C语言的节点写法一样,

迭代器的模拟

普通的迭代器

//迭代器
	template<class T>
	class _list_iterator
	{
	public:
		typedef ListNode<T> Node;
		typedef _list_iterator<T> Self;
		Node* node;

		_list_iterator(ListNode<T>* n)//需要注意的是这里尽量不要用引用
			:node(n)
		{
			
		}
		_list_iterator(const Self& n)
			:node(n.node)
		{
			
		}
		Self& operator++()//前置++
		{
			node = node->rigth;
			return *this;
		}
		Self operator++(int)//后置++
		{
			Self newnode(*this);
			node = node->rigth;
			return newnode;
		}
		Self& operator--()//前置--
		{
			node = node->left;
			return *this;
		}
			Self operator--(int)//后置--
		{
			Self newnode(*this);
			node = node->left;
			return newnode;
		}

		T& operator*()
		{
			return this->node->val;
		}
		bool operator!=(const Self& n)
		{
			return !(*this == n);
		}
		bool operator==(const Self& n)
		{
			return node == n.node;
		}
	};

在迭代器类的那里,我们不能使用地址来typedef,因为地址不连续,所以需要写一个迭代器类,迭代器类里面要进行运算符重载,必须重载* 、 != 、前后置++和–, 这里的迭代器只是一个普通的迭代器,如果要实现一个const迭代器就需要另外写法

const迭代器

我们明白const迭代器防止的是指向的内容不能修改不是迭代器本身不能修改,所以不能在普通迭代器使用const关键字修饰

// const 迭代器
	template<typename T>
	class _list_const_iterator
	{
	public:
		typedef ListNode<T> Node;
		typedef _list_const_iterator const_self;
		typedef const_self  Self;
		Node const* node;//这里可以不添加const修饰
		_list_const_iterator( const Node* n)
			:node(n)
		{

		}
		Self& operator++() //前置++
		{
			node = node->rigth;
			return *this;
		}
		Self operator++(int) //后置++
		{
			Self newnode(*this);
			node = node->rigth;
			return newnode;
		}
		Self& operator--()//前置--
		{
			node = node->left;
			return *this;
		}
		Self operator--(int)//后置--
		{
			Self newnode(*this);
			node = node->left;
			return newnode;
		}
		const T& operator*() const
		{
			return this->node->val;
		}
		bool operator!=(const Self& n) const
		{
			return !(*this == n);
		}
		bool operator==(const Self& n) const
		{
			return node == n.node;
		}
	};

这是和普通类相似很多的写法,唯一不同的就是operator那里返回值不同,但是这种写法冗余了,图中的很多函数都加了const修饰this,让起不能修改this的成员,需要注意的就是使用const修饰this, 要知道this的成员是否要修改,根据情况来定,
我们要清楚: const迭代器有两个作用一个是迭代器本身可以修改,一个是其指向的内容不能被修改,如果简单理解为 const iterator就是const迭代器,是错误的,因为这样写只能说明 该值不能被修改,违背了const迭代器的第一个作用.
方法2:
在普通迭代器上再增加一个类型,用来控制operator
的返回值

template<class T, class Ref>
	class _list_iterator
	{
	public:
		typedef ListNode<T> Node;
		typedef _list_iterator<T,Ref> Self;
		Node* node;

		_list_iterator(ListNode<T>* n)
			:node(n)
		{
			
		}
		_list_iterator(const Self& n)
			:node(n.node)
		{
			
		}
		Self& operator++()//前置++
		{
			node = node->rigth;
			return *this;
		}
		Self operator++(int)//后置++
		{
			Self newnode(*this);
			node = node->rigth;
			return newnode;
		}
		Self& operator--()//前置--
		{
			node = node->left;
			return *this;
		}
		Self operator--(int)//后置--
		{
			Self newnode(*this);
			node = node->left;
			return newnode;
		}

		Ref& operator*()
		{
			return this->node->val;
		}
		bool operator!=(const Self& n)
		{
			return !(*this == n);
		}
		bool operator==(const Self& n)
		{
			return node == n.node;
		}
	};

反向迭代器

这里我使用的方法是适配器的方法,套一个外壳,只要传入不同的迭代器就可以实现对应的++、–等功能

// 反向迭代器, 使用适配器的方法
	template<class T, class Ref,class Compart = _list_iterator<T, Ref>>
	class _list_reverse__iterator
	{
	public:
		typedef _list_reverse__iterator<T,Ref> Self;
		_list_reverse__iterator(Compart cp)
			:it(cp)
		{

		}
		Self& operator++()
		{
			it--;

			return *this;
		}
	/*	Self& operator++()const
		{
			it--;

			return *this;
		}*/
		Self operator++(int)
		{
			Compart ne = it;
			it--;
			return ne;
		}
	/*	Self operator++(int)const
		{
			Compart ne = it;
			it--;
			return ne;
		}*/
		Self& operator--()
		{
			it++;
			return it;
		}
	/*	Self& operator--()const
		{
			it++;
			return it;
		}*/
		Self operator--(int)
		{
			Compart ne = *this;
			it++;
			return ne;
		}
		/*Self operator--(int)const
		{
			Compart ne = *this;
			it++;
			return ne;
		}*/
		bool operator!=(const Self& iter)
		{
			return it != iter.it;
		}
		/*bool operator!=(const Self& iter)const
		{
			return it != iter.it;
		}*/
		bool operator==(const Self& iter)
		{
			return it == iter.it;
		}
	/*	bool operator==(const Self& iter)const
		{
			return it == iter.it;
		}*/
		
		Ref& operator*()
		{
			return *it;
		}
		/*Ref& operator*()const
		{
			return *it;
		}*/


	private:
		Compart it;

	};

这里重载了const修饰的this指针的运算符,可以不看,这里的原理就是, 只要传入不同的迭代器,然后进行对应的操作, 所以说,反向迭代器的实现,就可以解决const反向迭代器的实现了,可以说一举多得

重载->

这里有一个好玩的点

#include<iostream>
#include<list>
using namespace std;
namespace bit
{
	class AA
	{
	public:
		int a = 10;
		int b = 20;

	};
	template<class T>
	class BB
	{
	public:
		 T* operator->()
		{
			return &(this->t);
		}

	private:
		T t;
	};
}
int main()
{
	bit::BB<bit::AA> t;
	cout << t->a << endl;// t.operator->()->a
	cout << t->b << endl;//t.operator->()->b
	return 0;
}

需要注意的是这里这里c++会省略一个**->**,增加了可读性,这里本来有两个->,省略了一个,由此可见,我们如果要重载一个->就要注意了

list类:

//迭代器
	template<class T>
	class _list_iterator
	{
	public:
		typedef ListNode<T> Node;
		typedef _list_iterator<T> Self;
		Node* node;

		_list_iterator(ListNode<T>*& n)
			:node(n)
		{
			
		}
		_list_iterator(const Self& n)
			:node(n.node)
		{
			
		}
		Self& operator++()//前置++
		{
			node = node->rigth;
			return *this;
		}
		Self operator++(int)//后置++
		{
			Self newnode(*this);
			node = node->rigth;
			return newnode;
		}
		Self& operator--()//前置--
		{
			node = node->left;
			return *this;
		}
			Self operator--(int)//后置--
		{
			Self newnode(*this);
			node = node->left;
			return newnode;
		}

		T& operator*()
		{
			return this->node->val;
		}
		bool operator!=(const Self& n)
		{
			return !(*this == n);
		}
		bool operator==(const Self& n)
		{
			return node == n.node;
		}
	};
	//记得我们模拟实现的list要有哨兵位
	template<class T>
	class list
	{
	public:
		typedef ListNode<T> Node;
		typedef _list_iterator<T> iterator;

		list()//初始化,创建哨兵位
		{
			_head = new Node();
			_head->left = _head;
			_head->rigth = _head;
		}
		~list()
		{
			clear();
			delete this->_head;
			cout << "析构完毕" << endl;
		}
		list(list<T>& n)
		{
			//浅拷贝(容易野指针)
			//this->_head = n._head;
			_head = new Node();
			_head->left = _head;
			_head->rigth = _head;
			for ( const auto& e : n)
			{
				push_back(e);
			}
		}
		void swap(list<T>& n)
		{
			Node* swapelem = this->_head;
			this->_head = n._head;
			n._head = swapelem;
		}
		list<T>& operator=(list<T> n)
		{
			////方法1
			//if (this != &n)
			//{
			//	clear();
			//	for (const auto& e : n)
			//	{
			//		push_back(e);
			//	}
			//}
			
			//方法2
			swap(n);
			return *this;

		}
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				pop_front();
				it = begin();
			}
		}
		void push_back(const T& num)
		{
			//方法1
			/*Node* nextnode = new Node(num);
			_head->left->rigth = nextnode;
			_head->left = nextnode;
			nextnode->rigth = _head;*/
			//方法二
			inset(end(), num);
		}
		iterator begin()
		{
			iterator it(_head->rigth);
			return it;
			// return _head->rigth 隐式类型转换
		}
		iterator end()
		{
			//隐式类型转换
			return _head;
		}
		iterator inset(iterator pos, const T& num)
		{
			Node* cur = pos.node;//记得当前位置
			Node* prev = cur->left;//上一个
			Node* newnode = new Node(num);
			newnode->rigth = cur;
			cur->left = newnode;
			newnode->left = prev;
			prev->rigth = newnode;
			return newnode;

		}
		void push_front(const T& num)
		{
			inset(begin(), num);
		}
		iterator erase(iterator pos)
		{
			assert(pos != end());
			Node* prev = (pos.node)->left;
			Node* next = (pos.node)->rigth;
			prev->rigth = next;
			next->left = prev;
			delete pos.node;
			return next;
		}
		void pop_back()
		{
			erase(--end());
		}
		void pop_front()
		{
			erase(begin());
		}

	private:
		Node* _head;

	};

我们需要注意的就是迭代器和list 的初始化,
总代码代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<istream>
#include<list>
#include<iostream>
#include<assert.h>
using namespace std;
namespace bit
{
	//节点类
	template<class T>
	struct ListNode
	{
	public:
		ListNode<T>* left;
		ListNode<T>* rigth;
		T val;

		ListNode(const T& num = T())
			:left(nullptr)
			, rigth(nullptr)
			, val(num)
		{


		}
		bool operator==(const ListNode<T> n)
		{
			return this == &n;
		}
	};
	//迭代器
	template<class T, class Ref>
	class _list_iterator
	{
	public:
		typedef ListNode<T> Node;
		typedef _list_iterator<T, Ref> Self;
		Node* node;

		_list_iterator(ListNode<T>* n)
			:node(n)
		{

		}
		_list_iterator(const Self& n)
			:node(n.node)
		{

		}
		Self& operator++()//前置++
		{
			node = node->rigth;
			return *this;
		}
		Self operator++(int)//后置++
		{
			Self newnode(*this);
			node = node->rigth;
			return newnode;
		}
		Self& operator--()//前置--
		{
			node = node->left;
			return *this;
		}
		Self operator--(int)//后置--
		{
			Self newnode(*this);
			node = node->left;
			return newnode;
		}

		Ref& operator*()
		{
			return this->node->val;
		}
		bool operator!=(const Self& n)
		{
			return !(*this == n);
		}
		bool operator==(const Self& n)
		{
			return node == n.node;
		}
	};
	// 反向迭代器, 使用适配器的方法
	template<class T, class Ref,class Compart = _list_iterator<T, Ref>>
	class _list_reverse__iterator
	{
	public:
		typedef _list_reverse__iterator<T,Ref> Self;
		_list_reverse__iterator(Compart cp)
			:it(cp)
		{

		}
		Self& operator++()
		{
			it--;

			return *this;
		}
	/*	Self& operator++()const
		{
			it--;

			return *this;
		}*/
		Self operator++(int)
		{
			Compart ne = it;
			it--;
			return ne;
		}
	/*	Self operator++(int)const
		{
			Compart ne = it;
			it--;
			return ne;
		}*/
		Self& operator--()
		{
			it++;
			return it;
		}
	/*	Self& operator--()const
		{
			it++;
			return it;
		}*/
		Self operator--(int)
		{
			Compart ne = *this;
			it++;
			return ne;
		}
		/*Self operator--(int)const
		{
			Compart ne = *this;
			it++;
			return ne;
		}*/
		bool operator!=(const Self& iter)
		{
			return it != iter.it;
		}
		/*bool operator!=(const Self& iter)const
		{
			return it != iter.it;
		}*/
		bool operator==(const Self& iter)
		{
			return it == iter.it;
		}
	/*	bool operator==(const Self& iter)const
		{
			return it == iter.it;
		}*/
		
		Ref& operator*()
		{
			return *it;
		}
		/*Ref& operator*()const
		{
			return *it;
		}*/


	private:
		Compart it;

	};
	// const 迭代器
	template<typename T>
	class _list_const_iterator
	{
	public:
		typedef ListNode<T> Node;
		typedef _list_const_iterator const_self;
		typedef const_self  Self;
		Node const* node;
		_list_const_iterator(const Node*& n)
			:node(n)
		{

		}
		Self& operator++() //前置++
		{
			node = node->rigth;
			return *this;
		}
		Self operator++(int) //后置++
		{
			Self newnode(*this);
			node = node->rigth;
			return newnode;
		}
		Self& operator--()//前置--
		{
			node = node->left;
			return *this;
		}
		Self operator--(int)//后置--
		{
			Self newnode(*this);
			node = node->left;
			return newnode;
		}
		const T& operator*() const
		{
			return this->node->val;
		}
		bool operator!=(const Self& n) const
		{
			return !(*this == n);
		}
		bool operator==(const Self& n) const
		{
			return node == n.node;
		}


	};
	
	//记得我们模拟实现的list要有哨兵位
	template<class T>
	class list
	{
	public:
		typedef ListNode<T> Node;
		typedef _list_iterator<T, T> iterator;
		typedef _list_iterator<T, const T> const_iterator;
		typedef _list_reverse__iterator<T, T,iterator> reverse_iterator;
		typedef _list_reverse__iterator<T, const T,const_iterator> const_reverse_iterator;

		list()//初始化,创建哨兵位
		{
			_head = new Node();
			_head->left = _head;
			_head->rigth = _head;
		}
		~list()
		{
			clear();
			delete this->_head;
			cout << "析构完毕" << endl;
		}
		list(const list<T>& n)
		{
			//浅拷贝(容易野指针)
			//this->_head = n._head;
			_head = new Node();
			_head->left = _head;
			_head->rigth = _head;
			for (const auto& e : n)
			{
				push_back(e);
			}
		}
		void swap(list<T>& n)
		{
			Node* swapelem = this->_head;
			this->_head = n._head;
			n._head = swapelem;
		}
		list<T>& operator=(list<T> n)
		{
			////方法1
			//if (this != &n)
			//{
			//	clear();
			//	for (const auto& e : n)
			//	{
			//		push_back(e);
			//	}
			//}

			//方法2
			swap(n);
			return *this;

		}
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				pop_front();
				it = begin();
			}
		}
		void push_back(const T& num)
		{
			//方法1
			/*Node* nextnode = new Node(num);
			_head->left->rigth = nextnode;
			_head->left = nextnode;
			nextnode->rigth = _head;*/
			//方法二
			inset(end(), num);
		}
		iterator begin()
		{
			iterator it(_head->rigth);
			return it;
			// return _head->rigth 隐式类型转换
		}
	
		const_iterator begin() const
		{
			const_iterator it(_head->rigth);
			return it;
		}
		reverse_iterator rbegin()
		{
			return --end();
		}
		const_reverse_iterator rbegin() const
		{
			return --end();
		}
		iterator end()
		{
			//隐式类型转换
			return _head;
		}
		
		const_iterator end() const
		{
			const_iterator it(_head);
			return it;
		}
		reverse_iterator rend()
		{
			//隐式类型转换
			return end();
		}
		const_reverse_iterator rend()const
		{
			//隐式类型转换
			return end();
		}
		iterator inset(iterator pos, const T& num)
		{
			Node* cur = pos.node;//记得当前位置
			Node* prev = cur->left;//上一个
			Node* newnode = new Node(num);
			newnode->rigth = cur;
			cur->left = newnode;
			newnode->left = prev;
			prev->rigth = newnode;
			return newnode;

		}
		void push_front(const T& num)
		{
			inset(begin(), num);
		}
		iterator erase(iterator pos)
		{
			assert(pos != end());
			Node* prev = (pos.node)->left;
			Node* next = (pos.node)->rigth;
			prev->rigth = next;
			next->left = prev;
			delete pos.node;
			return next;
		}
		void pop_back()
		{
			erase(--end());
		}
		void pop_front()
		{
			erase(begin());
		}

	private:
		Node* _head;

	};

}
int main()
{
	bit::list<int> lt1;
	lt1.push_back(222);
	bit::list<int> lt;
	lt = lt1;
	lt.push_front(10);
	lt.push_front(12);
	lt.push_front(13);
	lt.push_front(14);
	lt.push_front(15);
	lt.push_front(16);
	lt.pop_back();
	lt.pop_front();
	
	//bit::list<int>::iterator it = lt.begin();
	//lt.erase(it);
	//lt.clear();
	//it = lt.begin();
	//while (it != lt.end())
	//{

	//	cout << *it << endl;
	//	it++;
	//}
	//it--;
	//cout << *it-- << endl;

	const bit::list<int> lt2(lt);
	bit::list<int>::const_reverse_iterator const_it = lt2.rbegin();

	while (const_it != lt2.rend())
	{

		cout << *const_it << endl;
		
		const_it++;
	}
	//for (auto& e : lt2)
	//{
	//	cout << e << endl;
	//}


	//for (const auto& e : lt)
	//{
	//	cout << e << endl;
	//}


	return 0;
}

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

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

相关文章

playwrite今日头条自动发帖

目的 大家好&#xff0c;我是watchpoints &#xff0c;一个只为自己打工程序员&#xff0c; watchpoints是我github用户名 &#xff0c;也是我的wechat 用户名&#xff0c; 每天看新闻浪费大量时间&#xff0c;写一个程序 自动提醒你21点远离手机 python实现 步骤1:自动登录 # …

在 Linux 9 上安装 Oracle 19c:克服兼容性问题 (INS-08101)

Oracle 数据库 19c 的基础版本 (19.3) 发布的时候还没有 Linux 9 &#xff0c;因此在Linux 9上面安装Oracle 19c会遇到很多兼容性问题。本文将探讨如何解决这些问题。 安装步骤 设置环境变量以绕过操作系统检查&#xff1a; Oracle 19.3 安装程序无法识别 Linux 9。 [WARNIN…

sql二次注入实战--2018年网顶杯

网址&#xff1a;BUUCTF在线评测 (buuoj.cn) 当我们进入后显示这个页面&#xff1a; 当我们第一次点击发帖的时候就会跳转到登陆页面&#xff0c;上面有提示&#xff0c;告诉我们账号为zhangwei,密码为zhangwei***&#xff1a; 这里我们可以使用bp抓包工具来进行暴力破解密码&…

《剑来》语句摘录(十二)

◆ 第二百零三章 休要略过不提 >> 怨怼与仇恨是快刀斩乱麻&#xff0c;一往无前。金铁相错&#xff0c;激起的火星&#xff0c;就是大丈夫的恩怨分明。无非敢作敢当。 愧疚和遗憾却是一把钝刀&#xff0c;刀刃上边的缺口&#xff0c;皆是曾经犯过的错误。关门磨刀即是后悔…

LVS四层架构部署

LVS四层架构部署 LVS集群的类型 lvs-nat&#xff1a; 修改请求报文的目标IP,多目标IP的DNATlvs-dr&#xff1a; 操纵封装新的MAC地址lvs-tun&#xff1a; 在原请求IP报文之外新加一个IP首部lvs-fullnat&#xff1a; 修改请求报文的源和目标IP LVS-NAT 工作流程 可以理解na…

主从备份(复制)

一、备份的三种类型 备份的三种主要类型包括热备份、逻辑备份和物理备份&#xff0c;每种备份类型都有其特定的应用场景和优缺点。 1. 热备份 定义&#xff1a; 热备份是在数据库或系统处于正常运行状态下进行的备份。这种备份方式允许在不停机的情况下对数据库或系统数据进…

用Python构建一个简单的神经网络

准备工作 首先我们需要使用到vscode 在终端 窗口下输入安装&#xff1a;pip3 install tensorflow pandas numpy keras 代码编写 导入库 import tensorflow as tf from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense import panda…

PyTorch深度学习实战(3)—— 小试牛刀:CIFAR-10分类

下面尝试从零搭建一个PyTorch模型来完成CIFAR-10数据集上的图像分类任务&#xff0c;步骤如下。 &#xff08;1&#xff09;使用torchvision加载并预处理CIFAR-10数据集。 &#xff08;2&#xff09;定义网络。 &#xff08;3&#xff09;定义损失函数和优化器。 &#xff08;4…

面向服务架构(SOA)介绍

在汽车电子电气架构还处于分布式时代时&#xff0c;汽车软件的开发方式主要是采用嵌入式软件进行开发&#xff0c;而随着汽车智能化程度的加深&#xff0c;更加复杂且多样的功能需求让汽车软件在复杂度上再上一层。在整车的自动驾驶方面&#xff0c;由于未来高阶自动驾驶能力的…

JavaScript constructor原型原型继承

constructor 在 JavaScript 中&#xff0c;构造函数是一种特殊的函数&#xff0c;使用 new 关键字来调用&#xff0c;用于创建对象实例。JavaScript 中的构造函数通常通过 function 关键字定义。 例如&#xff1a; function Person(name, age) {this.name name;this.age a…

C语言预处理:开启编程新境界

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C语言学习 贝蒂的主页&#xff1a;Betty‘s blog 1. 预处理符号 在C语言中&#xff0c;我们可以通过一些预定义符号查看文件的…

vue中post请求返回二进制流文件下载

1 .调用接口返回的如下图所示,此时看到是一个流文件 2.不管是get请求还是post请求都需要加上 下面这行代码 responseType: "blob", 3.我们自行二次封装的axios可能会导致乱码现象,建议直接用axios调用接口请求 4.关于Excel导出 POI 响应头设置 Content-Type: applica…

Tomcat高可用集群(实例详解)

一.环境准备 虚拟机的版本&#xff1a;VMware-workstation-full-15.5.6-16341506.exe系统镜像版本&#xff1a;CentOS-6.10-x86_64-bin-DVD1.iso&#xff0c;全新安装&#xff0c;桌面版&#xff0c;可上网系统内存大小&#xff1a;1GB系统硬盘大小&#xff1a;20GB连接工具版…

《决胜B端 产品经理升级之路》 知识点总结

什么是b端产品&#xff1f; b端产品是指面向企业或组织的经营管理问题&#xff0c;旨在解决企业规模、成本、效率、品质和风控等方面的产品。这些产品主要帮助企业提高运营效率、降低成本、改善品质和控制风险等。b端产品适用于各种行业和企业类型&#xff0c;可以为企业带来深…

WordPress原创插件:disable-gutenberg禁用古腾堡编辑器和小工具

WordPress原创插件&#xff1a;disable-gutenberg禁用古腾堡编辑器和小工具 disable-gutenberg插件下载:https://download.csdn.net/download/huayula/89616495

【zlm】针对单个设备的音频的编码的设置

目录 结论 原理 测试 结论 为了防止zlm音频配置里设置成opus优先&#xff0c;在国标推流时&#xff0c;调用push时&#xff0c;默认加上codecpcma 如下 https://10.60.100.196:10443/index/api/webrtc?applive&streamtest&typepush&codecpcma 原理 测试 …

ASP.Net Core设置接口根路径的方法

使用asp.net core开发微服务项目&#xff0c;需要给每个服务设置不同的根路径&#xff0c;这样既能使用网关转发请求&#xff0c;又方便对单个服务进行测试&#xff0c;保证请求路径的统一。 设置方法需要使用中间件&#xff0c;在Program.cs添加如下代码 app.UsePathBase(&qu…

量化投资基础(四)之AR、MA、ARMA与ARIMA模型

点赞、关注&#xff0c;养成良好习惯 Life is short, U need Python 量化投资基础系列&#xff0c;不断更新中 1 引言 时间序列经典模型主要有: 自回归模型&#xff08;Auto Regressive&#xff0c;AR&#xff09;移动回归模型&#xff08;Moving Average&#xff0c;MA&…

无线领夹麦克风哪个品牌好,哪款领夹式麦克风性价比高

随着自媒体行业的蓬勃发展&#xff0c;内容创作者对高质量音频设备的需求日益增长。无线领夹麦克风&#xff0c;凭借其便携性、高音质与灵活性&#xff0c;正逐渐成为视频制作、直播互动及日常Vlog记录的标配工具。其兴起不仅反映了创作者对专业录音品质的追求&#xff0c;也体…

Web安全学习

1 计算机网络与协议 1.1 网络基础 1.1.1 计算机通信网的组成 计算机网络由通信子网和资源子网组成。 通信子网&#xff1a;负责数据的无差错和有序传递&#xff0c;其处理功能包括差错控制、流量控制、路由选择、网络互连等。 资源子网&#xff1a;是计算机通信的本地系统环境…