vector

news2024/11/18 7:36:17

目录

  • vector的介绍和使用
    • vector的介绍
    • vector的使用
      • vector 空间增长问题
      • vector 迭代器失效问题。(重点)
    • vector与erase迭代器失效的代码
  • vector深度剖析及模拟实现
    • vector模拟实现代码
    • 使用memcpy拷贝问题
    • 动态二维数组理解
  • vector反向迭代器
    • reverse_iterator
    • vector.h

vector的介绍和使用

vector的介绍

  1. vector是表示可变大小数组的序列容器。
  2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素
    进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自
    动处理。
  3. 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小
    为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是
    一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大
    小。
  4. vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存
    储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是
    对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
  5. 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增
    长。
  6. 与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末
    尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list
    统一的迭代器和引用更好。

vector的使用

vector 空间增长问题

  • capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。
    这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是根据具体的需求定义
    的。vs是PJ版本STL,g++是SGI版本STL。
  • reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问
    题。
  • resize在开空间的同时还会进行初始化,影响size

vector 迭代器失效问题。(重点)

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了
封装,比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器底层对应指针所指向的
空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,
程序可能会崩溃)。
对于vector可能会导致其迭代器失效的操作有
  1. 会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、assign、
    push_back等。
  2. 指定位置元素的删除操作–erase
    (erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代
    器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是
    没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效
    了。)
  3. 注意:Linux下,g++编译器对迭代器失效的检测并不是非常严格,处理也没有vs下极端。
    ( SGI STL中,迭代器失效后,代码并不一定会崩溃,但是运行结果肯定不对,如果it不在begin和end范围内,肯定会崩溃的。)
  4. 与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效

迭代器失效解决办法:在使用前,对迭代器重新赋值即可

vector与erase迭代器失效的代码

在这里插入图片描述

vector深度剖析及模拟实现

在这里插入图片描述

vector模拟实现代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<assert.h>
#include<vector>
using namespace std;
/// 这里只实现了正向迭代器 //
namespace sz
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		iterator begin()
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}

		const_iterator begin() const
		{
			return _start;
		}

		const_iterator end() const
		{
			return _finish;
		}

		size_t capacity() const
		{
			return _end_of_storage - _start;
		}

		size_t size() const
		{
			return _finish - _start;
		}

		T& operator[](size_t pos)
		{
			assert(pos < size());

			return _start[pos];
		}


		const T& operator[](size_t pos) const
		{
			assert(pos < size());

			return _start[pos];
		}

		vector()
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{}

		// 拷贝构造
		// v1(v2)

		/// 写法一
		//vector(const vector<T>& v)
		//{
		//	_start = new T[v.size()]; // v.capacity()也可以
		//	//memcpy(_start, v._start, sizeof(T) * v.size());
		//	/// memcpy 不能解决vector<vector<int>>的拷贝问题,需要用到下面的方法
		//	for (size_t i = 0; i < size(); i++)
		//	{
		//		_start[i] = v._start[i];  // vector<vector<int>>相当于赋值拷贝,复制拷贝里面已经解决了深拷贝的问题
		//	}
		//	_finish = _start + v.size();
		//	_end_of_storage = _start + v.size();
		//}
		/// 写法二
		//vector(const vector<T>& v)
		//	:_start(nullptr)
		//	,_finish(nullptr)
		//	,_end_of_storage(nullptr)
		//{
		//	reserve(v.size());
		//for (const auto& e : v)
		//	{
		//		push_back(e);
		//	}
		//}

		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage, v._end_of_storage);
		}
		// 下面是带参的vector构造函数,使用了模板嵌套模板
		// 好处是象 vector<int> v(string迭代器) 一样可以传与vector<int>不一样的类型
		// 还有注意要写初始化列表来初始化
		template <class InputIterator>
		vector(InputIterator first, InputIterator last)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
		//vector(int n, const T& val = T()) 改为int可以避免vector<int>(10,1)错误但是不满住库中的参数形式
		// 库里面的解决办法是添加一个构造函数
		vector(int n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			for (size_t i = 0; i < n; i++)
			{
				push_back(val);
			}
		}

		vector(size_t n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			for (size_t i = 0; i < n; i++)
			{
				push_back(val);
			}
		}
		/// 写法三, 下面的拷贝构造需要依赖上面的swap和带参的构造函数
		// 注意初始化列表
		vector(const vector<T>& v)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			vector<T> tmp(v.begin(), v.end());
			swap(tmp);
		}

		~vector()
		{
			delete[] _start;
			_start = _finish = _end_of_storage = nullptr;
		}
		void resize(size_t n, const T& val = T())
		{
			// 1. 扩容 + 初始化
			// 
			if (n > capacity())
			{
				resever(n);
			}
			if (n > size())
			{
				while (_finish < _start + n)
				{
					*_finish = val;
					++_finish;
				}
			}
			else
			{
				_finish = _start + n;
			}
		}
		void resever(size_t n)
		{
			if (n > capacity())
			{
				size_t se = size();
				T* tmp = new T[n];
				// 要不要拷贝数据,刚开始_start为空,只需要扩容,不需要拷贝数据
				if (_start)
				{
					//memcpy(tmp, _start, sizeof(T)*sz);
					for (size_t i = 0; i < size(); ++i)
					{
						tmp[i] = _start[i];
					}
					delete[] _start;
				}
				//_start = tmp;
				///__finish = _start + size();
				//_end_of_storage = _start + n;
				///_finish = _start + size();这样的写法是错误的
				/// 因为size()中_finish - _start中_start已经发生改变与_finish不是指向同一块空间了
				///_finish就是要获取内存中元素的个数
				/// 解决办法:(1)先定义_finish = tmp + size(),在定义_start = tmp,可以保证_start没有改变
				/// 推荐(2) 在改变_start前先保留好长度,size_t se = size();
				_start = tmp;
				_finish = _start + se;
				_end_of_storage = _start + n;
			}
		}
		//左值指既能够出现在等号左边,也能出现在等号右边的变量;
		//右值则是只能出现在等号右边的变量
		//不加const引用只能是左值,像这样push_back("xxx")就不可以,所以要加const
		// 加引用是为了当T为自定义类型时,像string,list等,可以不用拷贝带来的消耗
		void push_back(const T& x)
		{
			if (_finish == _end_of_storage)
			{
				resever(capacity() == 0 ? 4 : capacity() * 2);
			}

			*_finish = x;
			++_finish;
		}

		void pop_back()
		{
			assert(_finish > _start);
			--_finish;
		}

		iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _start);
			assert(pos <= _finish);
			if (_finish == _end_of_storage)
			{
				size_t len = pos - _start;
				resever(capacity() == 0 ? 4 : capacity() * 2);
				pos = _start + len;
			}
			// 挪动数据
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = x;
			++_finish;
			return pos;
		}
		iterator erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos < _finish);

			iterator begin = pos + 1;
			while (begin < _finish)
			{
				*(begin - 1) = *begin;
				++begin;
			}

			//if (size() < capacity()/2)
			//{
			//	// 缩容 -- 以时间换空间
			//}

			--_finish;
			return pos;
		}

		T& front()
		{
			assert(size() > 0);

			return *_start;
		}

		T& back()
		{
			assert(size() > 0);

			return *(_finish - 1);
		}

		// v1 = v2
		vector<T>& operator=(vector<T> v)
		{
			swap(v);
			return *this;
		}

	private:
		iterator _start;
		iterator _finish;
		iterator _end_of_storage;
	};
}


void Textvector1()
{
	sz::vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);

	for (size_t i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	cout << endl;

	sz::vector<int>::iterator it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	for (const auto& e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

void Textvector2()
{
	sz::vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);

	//auto p = find(v.begin(), v.end(), 3);
	//if (p != v.end())
	//{
	//	v.insert(p, 30);
	//}
	//for (const auto& e : v)
	//{
	//	cout << e << " ";
	//}
	//cout << endl;


	//auto p = find(v.begin(), v.end(), 3);
	//if (p != v.end())
	//{
	//	v.insert(p, 30);

	//	cout << *p << endl;
	//	v.insert(p, 40);
	//}

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

	//v.insert(v.begin(), 1);

	auto p = find(v.begin(), v.end(), 3);
	if (p != v.end())
	{
		p = v.insert(p, 30);

		cout << *p << endl;
		v.insert(p, 40);
	}

	for (const auto& e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

void Textvector3()
{
	sz::vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(4);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);

	//auto pos = find(v.begin(), v.end(), 2);
	//if (pos != v.end())
	//{
	//	v.erase(pos);
	//}



	/// 删除所有的偶数
	// 错误的方法
	//auto it = v.begin();
	//while (it != v.end())
	//{
	//	if (*it % 2 == 0)
	//	{
	//		v.erase(it);
	//	}
	//	++it;
	//}


	/// 正确的方法
	auto it = v.begin();
	while (it != v.end())
	{
		if (*it % 2 == 0)
		{
			it = v.erase(it);
		}
		else
		{
			++it;
		}
	}

	for (const auto& e : v)
	{
		cout << e << " ";
	}
	cout << endl;

}


void Textvector4()
{
	sz::vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);

	for (const auto& e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	/// 用默认的拷贝构造函数
	// 1. 析构两次 2. 一个对象的修改会影响另一个对象
	sz::vector<int> v1(v);

	for (const auto& e : v1)
	{
		cout << e << " ";
	}
	cout << endl;


}
void Textvector5()
{
	std::string s("hello world");
	sz::vector<int> v(s.begin(), s.end());
	for (const auto& e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

void Textvector6()
{
	sz::vector<int> v(5);
	for (const auto& e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

void Textvector7()
{
	sz::vector<int> v;
	v.resize(10, 0);
	for (const auto& e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	sz::vector<int> v2;
	v2.resever(10);
	v2.push_back(1);
	v2.push_back(2);
	v2.push_back(3);
	v2.push_back(4);
	v2.push_back(5);
	v2.resize(8);
	for (const auto& e : v2)
	{
		cout << e << " ";
	}
	cout << endl;
}

void Textvector8()
{
	//sz::vector<char> v(10, 'c'); // 可以
	//sz::vector<string> v(10, "abc"); // 可以
	// 下面传入的是两个整形,string中定义的类中有多个构造函数,配备会出现问题
	// 本来要调用这个vector(const vector<T>&v)
	// 但是调用的是这个vector(InputIterator first, InputIterator last)
	//sz::vector<int> v(10, 1); // error
	//sz::vector<int> v((size_t)10, 1); // 不建议
	sz::vector<int> v(10, 1); // vector库里面的解决办法是添加一个构造函数

	for (const auto& e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}
int main()
{
	Textvector8();
	//const int& i = int(10);'

	//std::vector<int> v;

	return 0;
}

使用memcpy拷贝问题

假设模拟实现的vector中的reserve接口中,使用memcpy进行的拷贝,以下代码会发生什么问题?

int main()
{
	bite::vector<bite::string> v;
	v.push_back("1111");
	v.push_back("2222");
	v.push_back("3333");
	return 0;
}

问题分析:

  1. memcpy是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存空间中
  2. 如果拷贝的是自定义类型的元素,memcpy既高效又不会出错,但如果拷贝的是自定义类型元素,并且
    自定义类型元素中涉及到资源管理时,就会出错,因为memcpy的拷贝实际是浅拷贝。
    在这里插入图片描述

动态二维数组理解

在这里插入图片描述

vector反向迭代器

reverse_iterator

这里的反向迭代器不仅适用vector也适用ist

#pragma once
namespace sz
{
	// 复用, 迭代器适配器
	template<class Iterator, class Ret, class Ptr>
	class _reverse_iterator
	{
	public:
		Iterator _cur;

		typedef _reverse_iterator<Iterator, Ret, Ptr> RIterator;
		
		_reverse_iterator(Iterator it)
			:_cur(it)
		{}
		// 前置
		RIterator operator++()
		{
			--_cur;
			return *this;
		}
		// 后置
		RIterator operator++(int)
		{
			_cur--;
			return *this;
		}

		RIterator operator--()
		{
			++_cur;
			return *this;
		}

		RIterator operator--(int)
		{
			_cur++;
			return *this;
		}

		// 这里解引用要注意,先减减再返回
		// 注意list和vector 中end指向 list end指向哨兵位的节点  vector指向最后一个元素
		Ret operator*()
		{
			//return *_cur;
			auto tmp = _cur;
			--tmp;
			return *tmp;
		}

		Ptr operator->()
		{
			--_cur;
			//return _cur.operator->();
			return &(*_cur);
		}

		bool operator!=(const RIterator& it)
		{
			return _cur != it._cur;
		}
	};
}

vector.h

#pragma once

#include<iostream>
#include<assert.h>
#include<vector>
#include"reverse_iterator.h"

using namespace std;

namespace sz
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator; // 迭代器的类型是 T*
		typedef const T* const_iterator;

		// 反向迭代器
		typedef _reverse_iterator<iterator, T&, T*> reverse_iterator;
		typedef _reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;

		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}

		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}

		const_reverse_iterator rbegin() const
		{
			return reverse_iterator(end());
		}

		const_reverse_iterator rend() const
		{
			return reverse_iterator(begin());
		}

		iterator begin()
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}

		const_iterator begin() const
		{
			return _start;
		}

		const_iterator end() const
		{
			return _finish;
		}

		size_t capacity() const
		{
			return _end_of_storage - _start;
		}

		size_t size() const
		{
			return _finish - _start;
		}

		T& operator[](size_t pos)
		{
			assert(pos < size());

			return _start[pos];
		}


		const T& operator[](size_t pos) const
		{
			assert(pos < size());

			return _start[pos];
		}

		vector()
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{}

		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage, v._end_of_storage);
		}
		
		template <class InputIterator>
		vector(InputIterator first, InputIterator last)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		vector(int n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			for (size_t i = 0; i < n; i++)
			{
				push_back(val);
			}
		}

		vector(size_t n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			for (size_t i = 0; i < n; i++)
			{
				push_back(val);
			}
		}

		vector(const vector<T>& v)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			vector<T> tmp(v.begin(), v.end());
			swap(tmp);
		}

		~vector()
		{
			delete[] _start;
			_start = _finish = _end_of_storage = nullptr;
		}
		void resize(size_t n, const T& val = T())
		{
			// 1. 扩容 + 初始化
			// 
			if (n > capacity())
			{
				resever(n);
			}
			if (n > size())
			{
				while (_finish < _start + n)
				{
					*_finish = val;
					++_finish;
				}
			}
			else
			{
				_finish = _start + n;
			}
		}
		void resever(size_t n)
		{
			if (n > capacity())
			{
				size_t se = size();
				T* tmp = new T[n];
				// 要不要拷贝数据,刚开始_start为空,只需要扩容,不需要拷贝数据
				if (_start)
				{
					//memcpy(tmp, _start, sizeof(T)*sz);
					for (size_t i = 0; i < size(); ++i)
					{
						tmp[i] = _start[i];
					}
					delete[] _start;
				}
				_start = tmp;
				_finish = _start + se;
				_end_of_storage = _start + n;
			}
		}

		void push_back(const T& x)
		{
			if (_finish == _end_of_storage)
			{
				resever(capacity() == 0 ? 4 : capacity() * 2);
			}

			*_finish = x;
			++_finish;
		}

		void pop_back()
		{
			assert(_finish > _start);
			--_finish;
		}

		iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _start);
			assert(pos <= _finish);
			if (_finish == _end_of_storage)
			{
				size_t len = pos - _start;
				resever(capacity() == 0 ? 4 : capacity() * 2);
				pos = _start + len;
			}
			// 挪动数据
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = x;
			++_finish;
			return pos;
		}
		iterator erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos < _finish);

			iterator begin = pos + 1;
			while (begin < _finish)
			{
				*(begin - 1) = *begin;
				++begin;
			}

			--_finish;
			return pos;
		}

		T& front()
		{
			assert(size() > 0);

			return *_start;
		}

		T& back()
		{
			assert(size() > 0);

			return *(_finish - 1);
		}

		// v1 = v2
		vector<T>& operator=(vector<T> v)
		{
			swap(v);
			return *this;
		}

	private:
		iterator _start;
		iterator _finish;
		iterator _end_of_storage;
	};
}



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

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

相关文章

Android开发进阶——Coil对比Glide分析

Coil概述 Coil是Android上的一个全新的图片加载框架&#xff0c;它的全名叫做coroutine image loader,即协程图片加载库。 与传统的图片加载库Glide&#xff0c;Picasso或Fresco等相比。该具有轻量&#xff08;只有大约1500个方法&#xff09;、快、易于使用、更现代的API等优…

【Vue项目搭建】vue-admin-template修改(2)

接上文、、 --------------------------------------------------------- 优化登录 单独封装路由守卫 &#xff0c;设置白名单&#xff0c;permission.js&#xff0c;鉴权 跳转动画优化&#xff08;使用NProgress插件&#xff09; 显示logo svg 改填充颜色 stroke //画线颜色…

小题 错题总结

要是对象具有序列化&#xff0c;应该实现的接口是 Java.IO.Serializable在 JVM 内存划分中 &#xff0c;方法通常存储在 方法区多态的3种表现形式&#xff1a; 继承重写 重载 向上转型Java 中继承可以间接继承&#xff0c;即便中间跨过一个类&#xff0c;栗子&#xff1a;所有…

一文读懂Linux内核中的Device mapper映射机制

本文结合具体代码对 Linux 内核中的 device mapper 映射机制进行了介绍。Device mapper 是 Linux 2.6 内核中提供的一种从逻辑设备到物理设备的映射框架机制&#xff0c;在该机制下&#xff0c;用户可以很方便的根据自己的需要制定实现存储资源的管理策略&#xff0c;当前比较流…

基于PHP的动漫电影信息管理系统

有需要请私信或看评论链接哦 可远程调试 基于PHP的动漫电影管理系统一 介绍 此动漫电影信息管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员&#xff0c;用户注册登录后可观看/下载/收藏/留言/评分动漫电影等&#xff0c…

Multi-Channel PCe QDMARDMA Subsystem

可交付资料&#xff1a; 1. 详细的用户手册 2. Design File&#xff1a;Post-synthesis EDIF netlist or RTL Source 3. Timing and layout constraints&#xff0c;Test or Design Example Project 4. 技术支持&#xff1a;邮件&#xff0c;电话&#xff0c;现场&…

隐私计算概述

1. 基本概念 隐私计算是指在保证数据提供方不泄露原始数据的前提下,对数据进行分析计算的一些列信息技术,保障数据在流通和融合过程中的“可用不可见”。 从技术交付出发,隐私计算是众多学科的交叉融合技术,目前主流的隐私计算技术分为三大方向:第一类是多方安全计算为代…

linux内核中断

目录 硬中断特点 中断API 线程中断 系统标准的优先级顺序 中断信息查看 中断上半部与下半部 软中断与并发 硬中断特点 优先级最高中断函数在中断上下文中&#xff0c;不能阻塞不要间接或直接调用shedule() 在申请内存空间时&#xff0c;使用GFP_ATOMIC 标志&#xff08…

Blender——苹果纹理绘制

效果图 前言 在进行纹理绘制之前&#xff0c;首先要具有苹果三维模型。 关于苹果的建模请参考&#xff1a;Blender——“苹果”建模_行秋的博客 1.苹果UV的展开 1.1首先点击UV Eidting&#xff0c;滑动三维模型&#xff0c;使其大小适中。 1.2打开左上角的UV选区同步&#x…

IPv6 的地址(计算机网络-网络层)

目录 IPv6地址的表示方法 IPv6的分类 IPv6 全球单播地址 IPv6 多播地址 IPv6地址的表示方法 在 IPv6 中&#xff0c;每个地址占 128 位&#xff0c;地址空间大于 3.4 *10^ 38 。在想象得到的将来&#xff0c;IPv6的地址空间是不可能用完的 128位的IPv6地址使用冒号十六进制记…

玩以太坊链上项目的必备技能(库 [library]-Solidity之旅十七)

库&#xff08;library&#xff09; 作为开发者的您&#xff0c;想必对项目中重复使用的工具函数&#xff0c;抽取到一个公共中&#xff0c;以便可以在您项目中的其它位置可调用。 而 Solidity 与您所熟知的没有什么不同&#xff0c;它也是用来实现可重复调用&#xff0c;且还…

基于 Traefik 的激进 TLS 安全配置实践

前言 Traefik是一个现代的HTTP反向代理和负载均衡器&#xff0c;使部署微服务变得容易。 Traefik可以与现有的多种基础设施组件&#xff08;Docker、Swarm模式、Kubernetes、Marathon、Consul、Etcd、Rancher、Amazon ECS...&#xff09;集成&#xff0c;并自动和动态地配置自…

力扣(39.40)补9.20

目前打算刷些算法题&#xff0c;数据结构的题暂时放一放吧。 39.组合总和 不会&#xff0c;毕竟好久没做回溯了。 看了这个图会好理解很多呦。 class Solution { List<List<Integer>> ansnew ArrayList<>(); List<Integer> listnew ArrayList<>(…

AcWing算法学习之动态规划(基础)

背包问题 01背包问题 思路&#xff1a; 01背包问题&#xff0c;表示每个物品要么放&#xff0c;要么不放。从集合的角度分析DP问题&#xff0c;状态表示为&#xff1a;选择前i个物品&#xff0c;总体积小于等于j的选法的集合&#xff0c;属性f[i][j]表示价值的最大值。状态计算…

正交编码器数字滤波器(二)

正交编码器数字滤波器&#xff08;一&#xff09;电路初画完了&#xff0c;正交编码器数字滤波器&#xff08;二&#xff09;把核心部分用HDL描述语言实现了&#xff0c;放在一个小芯片里。 上面的整张图上&#xff0c;截出下面的小图&#xff0c;就用古老的ABEL工具实现它。 这…

高斯函数和C++简单实现

高斯函数在科学和工程中有广泛应用&#xff1b;其定义为&#xff0c; 其一般图像为&#xff0c; 高斯函数的图形在形状上像一个倒悬着的钟&#xff1b;参数a指高斯曲线的峰值&#xff0c;b为其对应的横坐标&#xff0c;c即标准差&#xff08;有时也叫高斯RMS宽值&#xff09;&a…

【1754. 构造字典序最大的合并字符串】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你两个字符串 word1 和 word2 。你需要按下述方式构造一个新字符串 merge &#xff1a;如果 word1 或 word2 非空&#xff0c;选择 下面选项之一 继续操作&#xff1a; 如果 word1 非空&#xff0…

Python常用基础语法知识点大全

介绍 Python 是一门独特的语言&#xff0c;快速浏览一下他的要点&#xff1a; 面向对象&#xff1a;每一个变量都是一个类&#xff0c;有其自己的属性&#xff08;attribute&#xff09;与方法&#xff08;method&#xff09;。语法块&#xff1a;用缩进&#xff08;四个空格…

Qml 中用 Shader 实现圣诞树旋转灯

一、前言 2022年圣诞节到来啦&#xff0c;很高兴这次我们又能一起度过~ 这次给大家带来一个简单漂亮圣诞树灯。 当然了&#xff0c;本篇文章主要是讲解一下如何在 Qml 中使用 GLSL 来实现自己的特效。 至于代码嘛&#xff0c;我比较喜欢在 Shaderjoy 上寻找&#xff0c;那里有很…

Biotin-PEG-Biotin,生物素-聚乙二醇-生物素聚乙二醇试剂供应

一&#xff1a;产品描述 1、名称 英文&#xff1a;Biotin-PEG-Biotin 中文&#xff1a;生物素-聚乙二醇-生物素 2、CAS编号&#xff1a;N/A 3、所属分类&#xff1a;Biotin PEG 4、分子量&#xff1a;可定制&#xff0c;2000/10000/3400/1000/20000/500 5、质量控制&…