【C++】-- 海量数据处理

news2024/11/19 20:44:13

目录

位图

位图概念的引入

位图的实现

实现功能

开辟bit空间

数据输入set

数据删除reset

数据确认test

代码汇总

容器位图的衍生使用

布隆过滤器

布隆过滤器提出

布隆过滤器概念

​布隆过滤器的实现

布隆过滤器的删除

布隆过滤器的特点

​布隆过滤器的误判率

​布隆过滤器的使用场景

精准查询 - 不允许误判

简陋查询 - 允许误判

哈希切割


        所谓海量数据处理,就是指数据量太大,无法在较短时间内迅速解决,或者无法一次性装入内存。所以对于海量数据处理方法的运用是相关重要的。

对于位图布隆过滤器哈希切割需要哈希算法的思维。

【C++】-- 哈希(上万字详细配图配代码从执行一步步讲解)_川入的博客-CSDN博客

位图

位图概念的引入

题#:给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。


解题思路通常为:

  1. 遍历(但是找一个数据时间复杂度就为O(N))
  2. 排序(O(NlogN)),然后利用二分查找(O(logN)。(40亿个无符号整数约等于16G,光看内存所需就是极为恐怖的)
  3. 利用位图解决。

        位图的原理简单来说就是一个计数排序。不同的是每一个元素只有一个bit位的大小,就是说,其只有0与1两种状态数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。比如:

        由于没有字节的类型于是需要我们自行进行分割使用,所以使用char或int类型的数组皆可。

        所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的。

位图的实现

实现功能

#include<vector>
using namespace std;
namespace cr
{
	template<size_t N> // 非类型模板参数 N为需开辟的bit位个数
	class bitset
	{
	public:
		//开辟bit空间
		bitset();

		//数据输入set
		void set(size_t x);

		//数据删除reset
		void reset(size_t x);

		//数据确认test
		bool test(size_t x);
	private:
		vector<char> _bits; // 此处采取vector容器实现
	};
}

开辟bit空间

        所知N为需开辟的bit位个数,而我们利用vector<char>容器开辟了一段数组,而8bit位为1byte:

//开辟bit空间
bitset()
{
	_bits.resize(N / 8 + 1, 0);
}

        由于 N / 8 是会省去余数。所以,时常会因为 N / 8 的除不净,而导致的开辟空间不足。而又因为采取的容器是vector<char>容器,所以一次空间开辟至少为char(8bit),所以只能在 N / 8 的基础上 + 1。

        由于位图是利用bit位的0与1判断数据是否存在,所以数据置0是至关重要的。

数据输入set

//数据输入set
void set(size_t x)
{
	size_t i = x / 8;
	size_t j = x % 8;

	_bits[i] |= (1 << j);
}

        因为底层采取的是vector<char>容器,所以每8bit位就是vector<char>容器实现的数组的一位。所以根据x / 8判断其应在char数组的哪一位中。而x % 8即为其在此位中的哪一个字节。

        由于是位操作。即利用位操作符 << 数据 1 ,保证只有数据的位置为1,然后利用位操作符 | 的有1即为1。记录数据是否存在。

数据删除reset

//数据删除reset
void reset(size_t x)
{
	size_t i = x / 8;
	size_t j = x % 8;

	_bits[i] &= ~(1 << j);
}

        因为底层采取的是vector<char>容器,所以每8bit位就是vector<char>容器实现的数组的一位。所以根据x / 8判断其应在char数组的哪一位中。而x % 8即为其在此位中的哪一个字节。

        由于是位操作。即利用位操作符 << 数据 1 并取反,保证只有数据的位置为0,然后利用位操作符 & 的都为1才是1。将存在的数据记录删除。

数据确认test

//数据确认test
bool test(size_t x)
{
	size_t i = x / 8;
	size_t j = x % 8;

	return _bits[i] & (1 << j);
}

        因为底层采取的是vector<char>容器,所以每8bit位就是vector<char>容器实现的数组的一位。所以根据x / 8判断其应在char数组的哪一位中。而x % 8即为其在此位中的哪一个字节。

        由于是位操作。即利用位操作符 << 数据 1 ,保证只有数据的位置为1,然后利用位操作符 & 的都为1才是1。判断数据是否存在。

代码汇总

#include<iostream>
#include<vector>
using namespace std;
namespace cr
{
	template<size_t N> // 非类型模板参数
	class bitset
	{
	public:
		//开辟bit空间
		bitset()
		{
			_bits.resize(N / 8 + 1, 0);
		}

		//数据输入set
		void set(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;

			_bits[i] |= (1 << j);
		}

		//数据删除reset
		void reset(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;

			_bits[i] &= ~(1 << j);
		}

		//数据确认test
		bool test(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;

			return _bits[i] & (1 << j);
		}

	private:
		vector<char> _bits;
	};
}

int main()
{
	cr::bitset<100> bs;
	bs.set(8);
	bs.set(9);
	bs.set(20);

	cout << bs.test(8) << endl;
	cout << bs.test(9) << endl;
	cout << bs.test(20) << endl;

	bs.reset(8);
	bs.reset(9);
	bs.reset(20);

	cout << bs.test(8) << endl;
	cout << bs.test(9) << endl;
	cout << bs.test(20) << endl;
	return 0;
}

位图的应用

  1. 快速查找某个数据是否在一个集合中。
  2. 排序 + 去重。
  3. 求两个集合的交集、并集等。
  4. 操作系统中磁盘块标记。

     位图对于处理大量数据很方便,但是只能运用于整数。

位图的特点

  1. 快、节省空间。
  2. 相对局限,只能映射处理整形。

     由于位图只能映射处理整形,于是对此我们要采取新的方式:布隆过滤器

STL中有bitset(位图)

容器位图的衍生使用

#题:给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?


解题思路:

        使用两个bitset(位图),分别记录两个文件中的数据的存在状态,最后将两个两个bitset(位图)结合(映射位都是1的值就是交集)。

Note:

        对于bitset容器的空间开辟使用bitset<-1> bs;(数据的范围与个数无关,所以我们只需要取到整数的大小范围,即:(size_t) -1)

#题: 1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数

解题思路:
        利用两个位图进行计数。

template<size_t N>
class twobitset
{
public:
	void set(size_t n)
	{
		bool insert1 = _bs1.test(n);
		bool insert2 = _bs2.test(n);

		if (insert1 == false && insert2 == false) // 0次 + 1
		{
			_bs1.set(n);
		}
		else if (insert1 == true && insert2 == false) // 1次 + 1
		{
			_bs2.set(n);
			_bs1.reset(n);
		}
		else if (insert1 == false && insert2 == true) // 2次 + 1
		{
			_bs1.set(n);
		}
	}

	// 此题不需要
	//void reset(size_t n)
	//{
	//	bool erase1 = _bs1.test(n);
	//	bool erase2 = _bs2.test(n);

	//	if (erase1 == true && erase2 == true) // 3次 - 1
	//	{
	//		_bs1.reset(n);
	//	}
	//	else if (erase1 == false && erase2 == true) // 2次 - 1
	//	{
	//		_bs2.reset(n);
	//		_bs1.set(n);
	//	}
	//	else if (insert1 == true && insert2 == false) // 1次 - 1
	//	{
	//		_bs1.reset(n);
	//	}
	//}

	// 找到只出现一次和二次的
	void print_once_twice_num()
	{
		for (size_t i = 0; i < N; ++i)
		{
			if (!(_bs1.test(i) == true && _bs2.test(i) == true))
			{
				cout << i << endl;
			}
		}
	}

private:
	bitset<N> _bs1; // 低位
	bitset<N> _bs2; // 高位
};

布隆过滤器

布隆过滤器提出

        我们在使用新闻客户端看新闻时,它会给我们不停地推荐新的内容,它每次推荐时要去重,去掉那些已经看过的内容。

​        问题来了,新闻客户端推荐系统如何实现推送去重的? 用服务器记录了用户看过的所有历史记录,当推荐系统推荐新闻时会从每个用户的历史记录里进行筛选,过滤掉那些已经存在的记录。 如何快速查找呢?

  1. 用哈希表存储用户记录,缺点:浪费空间
  2. 用位图存储用户记录,缺点:位图一般只能处理整形,如果内容编号是字符串,就无法处理了
  3. 将哈希与位图结合,即布隆过滤器

布隆过滤器概念

        布隆过滤器是由布隆(Burton Howard Bloom)在1970年提出的 一种紧凑型的、比较巧妙的概率型数据结构,特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”,它是用多个哈希函数,将一个数据映射到位图结构中。此种方式不仅可以提升查询效率,也可以节省大量的内存空间

        其本质上就是一个位图,对于位图我们知道:其是用每一位来存放某种状态,是适用于海量数据,用来判断某个数据存不存在的。这正映衬着使用新闻客户端看新闻时,不停地推荐新的内容,每次推荐时的去重。

        可是,内容是由字符串代表的,而字符串是有很多的状态。字符的不同,长度的不同等,皆会导致字符串转换的数值会有重复。这代表,如果我们使用位图完全同样的思维,会导致大量资源因为哈希地址的相同而被判断为出现过。

        于是,如何防止大量不同的字符串因为哈希地址的相同而导致的判断不准确就是重点:

采用多个位置映射

        理论而言:一个值映射的位越多,误判的概率越低。但是也不能映射的太多,映射位越多,那么空间的消耗就越多。

(此处采取三个位映射)

        采取多个位映射只能一定程度上的减少误判,并不能完全的避免。

如何选择哈希函数个数和布隆过滤器长度

(下列数据来自于链接中的知乎) 

​​        选择适合的 k 和 m 值公式:

​        此文,我们使用第二公式(通过:3个哈希函数,ln2 ≈ 0.693):

布隆过滤器的实现

        采取对bitset(位图)的再封装实现。

字符串哈希算法

struct HashBKDR
{
	// BKDR
	size_t operator()(const string& key)
	{
		size_t val = 0;
		for (auto ch : key)
		{
			val *= 131;
			val += ch;
		}

		return val;
	}
};

struct HashAP
{
	// BKDR
	size_t operator()(const string& key)
	{
		size_t hash = 0;
		for (size_t i = 0; i < key.size(); i++)
		{
			if ((i & 1) == 0)
			{
				hash ^= ((hash << 7) ^ key[i] ^ (hash >> 3));
			}
			else
			{
				hash ^= (~((hash << 11) ^ key[i] ^ (hash >> 5)));
			}
		}
		return hash;
	}
};

struct HashDJB
{
	// BKDR
	size_t operator()(const string& key)
	{
		size_t hash = 5381;
		for (auto ch : key)
		{
			hash += (hash << 5) + ch;
		}

		return hash;
	}
};

// N表示准备要映射N个值
template<size_t N
    , class K = string, class Hash1 = HashBKDR
    , class Hash2 = HashAP, class Hash3 = HashDJB>
class BloomFilter
{
public:
	void Set(const K& key)
	{
		size_t hash1 = Hash1()(key) % (_ratio * N);
		_bits->set(hash1);

		size_t hash2 = Hash2()(key) % (_ratio * N);
		_bits->set(hash2);

		size_t hash3 = Hash3()(key) % (_ratio * N);
		_bits->set(hash3);
	}

	bool Test(const K& key)
	{
		size_t hash1 = Hash1()(key) % (_ratio * N);
		if (!_bits->test(hash1))
			return false; // 准确的

		size_t hash2 = Hash2()(key) % (_ratio * N);
		if (!_bits->test(hash2))
			return false; // 准确的

		size_t hash3 = Hash3()(key) % (_ratio * N);
		if (!_bits->test(hash3))
			return false;  // 准确的

		return true; // 可能存在误判
	}

	// 此处不支持删除
	//void Reset(const K& key);

private:
	const static size_t _ratio = 3; //误判过高可以往上加
	std::bitset<_ratio* N>* _bits = new std::bitset<_ratio* N>;
};

int main()
{
	BloomFilter<10> bf;
	string arr1[] = { "苹果", "西瓜", "阿里", "美团", "苹果", "字节", "西瓜", "苹果", "香蕉", "苹果", "腾讯" };

	for (auto& str : arr1)
	{
		bf.Set(str);
	}

	// 相同字符串的判断
	for (auto& str : arr1)
	{
		cout << bf.Test(str) << " ";
	}
	cout << endl << endl;

	// 相似字符串的判断
	string arr2[] = { "苹果核", "西瓜", "阿里巴巴", "美团", "苹果皮", "字节"};

	for (auto& str : arr2)
	{
		cout << str << ":" << bf.Test(str) << endl;
	}
}

布隆过滤器的删除

        一般不支持删除,因为支持的话很有可能干扰到其他值。毕竟一个数据占多个哈希地址位,是会干扰到其他的数据的,有可能多个数据映射了同一个位置,毕竟多个哈希地址有一个不存在,即数据不存在。

        如果一定要支持删除,那么可以采取计数的方式:

​利用多个bitset(位图)进行计数型的布隆过滤器实现。

  • 1个位图:1(计数最大为:1)
  • 2个位图:11(计数最大为:3)
  • 3个位图:111(计数最大为:7)
  • ……以此类推

布隆过滤器的特点

        由于其采用的是一个或多个bitset(位图)结合多个哈希地址映射实现,所以对于数据的存在是有误差的:

  • 在:不准确的,存在误差的
  • 不在:准确的,不存在误判

​布隆过滤器的误判率

struct HashBKDR
{
	// BKDR
	size_t operator()(const string& key)
	{
		size_t val = 0;
		for (auto ch : key)
		{
			val *= 131;
			val += ch;
		}

		return val;
	}
};

struct HashAP
{
	// BKDR
	size_t operator()(const string& key)
	{
		size_t hash = 0;
		for (size_t i = 0; i < key.size(); i++)
		{
			if ((i & 1) == 0)
			{
				hash ^= ((hash << 7) ^ key[i] ^ (hash >> 3));
			}
			else
			{
				hash ^= (~((hash << 11) ^ key[i] ^ (hash >> 5)));
			}
		}
		return hash;
	}
};

struct HashDJB
{
	// BKDR
	size_t operator()(const string& key)
	{
		size_t hash = 5381;
		for (auto ch : key)
		{
			hash += (hash << 5) + ch;
		}

		return hash;
	}
};

// N表示准备要映射N个值
template<size_t N
	, class K = string, class Hash1 = HashBKDR
	, class Hash2 = HashAP, class Hash3 = HashDJB>
class BloomFilter
{
public:
	void Set(const K& key)
	{
		size_t hash1 = Hash1()(key) % (_ratio * N);
		_bits->set(hash1);

		size_t hash2 = Hash2()(key) % (_ratio * N);
		_bits->set(hash2);

		size_t hash3 = Hash3()(key) % (_ratio * N);
		_bits->set(hash3);
	}

	bool Test(const K& key)
	{
		size_t hash1 = Hash1()(key) % (_ratio * N);
		if (!_bits->test(hash1))
			return false; // 准确的

		size_t hash2 = Hash2()(key) % (_ratio * N);
		if (!_bits->test(hash2))
			return false; // 准确的

		size_t hash3 = Hash3()(key) % (_ratio * N);
		if (!_bits->test(hash3))
			return false;  // 准确的

		return true; // 可能存在误判
	}

	// 此处不支持删除
	//void Reset(const K& key);

private:
	const static size_t _ratio = 3; //误判过高可以往上加
	std::bitset<_ratio* N>* _bits = new std::bitset<_ratio* N>;
};

void TestBloomFilter()
{
	srand(time(0));
	const size_t N = 100000;
	BloomFilter<N> bf;

	std::vector<std::string> v1;
	std::string url = "https://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html";

	for (size_t i = 0; i < N; ++i)
	{
		v1.push_back(url + std::to_string(1234 + i));
	}

	for (auto& str : v1)
	{
		bf.Set(str);
	}

	// 相似(通过相同的字符串向后追加)
	std::vector<std::string> v2;
	for (size_t i = 0; i < N; ++i)
	{
		std::string url = "http://www.cnblogs.com/-clq/archive/2021/05/31/2528153.html";
		url += std::to_string(rand() + i);
		v2.push_back(url);
	}

	size_t n2 = 0;
	for (auto& str : v2)
	{
		if (bf.Test(str))
		{
			++n2;
		}
	}
	cout << "相似字符串误判率:" << (double)n2 / (double)N << endl;

	// 不相识
	std::vector<std::string> v3;
	for (size_t i = 0; i < N; ++i)
	{
		string url = "zhihu.com";
		url += std::to_string(rand() + i);
		v3.push_back(url);
	}

	size_t n3 = 0;
	for (auto& str : v3)
	{
		if (bf.Test(str))
		{
			++n3;
		}
	}
	cout << "不相似字符串误判率:" << (double)n3 / (double)N << endl;
}

int main()
{
    // 测试误判率
    TestBloomFilter();
    return 0;
}

​布隆过滤器的使用场景

精准查询 - 不允许误判

        在日常生活中时常会进行罪犯的抓捕,而对于罪犯的抓捕需要提取一些数据到电脑中,在利用这些数据到海量的数据库中寻找。但是,数据库的大小是海量的,大到不是一台移动电脑就能存下的,甚至需要数台服务器存储。如果可疑的数据一一到数据库中寻找,会因为如:硬盘查询速度缓慢,数据总量太多,网络的延迟等,都会造成长时间数据搜索。

        这个时候就需要利用布隆过滤器对数据进行过滤,将大量的可疑数据在电脑中就进行一次大筛选。

简陋查询 - 允许误判

        在日常生生活中,针对于某个游戏、某个app需要进行用户注册的时候,有一项选择是用户名的注册。有时候就会提醒你,你的用户名与他人相撞,需要更改用户名,这个时候,系统对于用户名是否有人使用的查询就是使用布隆过滤器。因为系统并没有必要精准的查询用户名是否真正的被占用。

哈希切割

#题:给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法。


解题思路:

哈希切割

  1. 假设每个query是30byte,则100亿query需要的空间为:3000亿byte约等于300G(这对于内存来说是一个恐怖的数据,所以需要用到哈希切分)
  2. 假设两个文件分别叫A和B

#题:给一个超过100G大小的log fifile, log中存着IP地址, 设计算法找到出现次数最多的IP地址?


解题思路:

哈希切割

        与上一题同样的道理,只不过最后用的不是set,而是map,通过编号相同的小文件Ai和Bi组成的map中,找到出现最多的。


#附加:与上题条件相同,如何找到top K的IP?

        通过前面,编号相同的小文件组成的map的情况下,写一个K个数据的小根堆,再通过一一个map,以此筛选top K

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

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

相关文章

【电动车】基于削峰填谷的电动汽车多目标优化调度策略研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

计算机组成原理复习:计算机系统概述

1. 计算机系统概述 1.1 计算机系统的层次结构 &#xff08;1&#xff09; 硬件上&#xff0c;计算机系统可以分为五大功能部件&#xff1a; 运算器、控制器、存储器、输入设备、输出设备 将围绕其工作原理、逻辑实现、设计方法以及相互连接构成整机的方法展开 在典型的冯诺…

Android metaRTC6.0 编译指南

概述 metaRTC新版本优化了安卓系统支持&#xff0c;demo将C和C生成lib库&#xff0c;在lib库上提供了纯Java的webRTC推拉流demo。 demo支持软硬编解码&#xff0c;软编码为openh264&#xff0c;软解码为yangh264decoder&#xff0c;gpu编解码为mediacodec。 metaRTC android…

全长扩增子医学版新增内容来啦(一)

随着全长扩增子报告内容的扩充&#xff0c;医学版报告单的呼声越来越高&#xff0c;今天就给大家介绍一下凌恩生物针对医学客户&#xff0c;变更/新增了哪些报告内容~ 首先我们来看一下变更的内容吧&#xff01; CCA/RDA分析、PICRUSt2功能预测、随机森林-biomarker鉴定、随机…

多线程之Thread类常见方法及线程的状态

Thread类常见方法&#xff1a; 创建、启动线程、终止线程、线程等待、获取线程实例、线程休眠 1.关于如何创建线程&#xff0c;在专栏的上一篇文章已经谈到了有5中创建线程的方式。 2.启动线程&#xff08;t.start&#xff09;&#xff1a;调用 start 方法, 才在操作系统的底…

ArcGIS基础实验操作100例--实验39编辑公共边与顶点

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验39 编辑公共边与顶点 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;1&…

《操作系统-真象还原》14. 文件系统

文章目录文件系统概念inode目录项与目录通过文件名查找文件的流程超级块与文件系统布局文件控制块 —— FCB创建文件系统创建相关结构创建文件系统挂载分区文件描述符文件描述符和文件表文件描述符文件表文件描述符与 inode 关联关系文件描述符的实现文件操作相关的基础函数ino…

单例模式

单例模式 1. 单例模式介绍 单例模式可以说是整个设计中最简单的模式之一&#xff0c;而且这种方式即使在没有看设计模式相关资料也会常用在编码开发中。 因为在编程开发中经常会遇到这样一种场景&#xff0c;那就是需要保证一个类只有一个实例哪怕多线程同时访问&#xff0c;…

C#语言实例源码系列-实现IC卡的读写

专栏分享点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册 &#x1f449;关于作者 众所周知&#xff0c;人生是一个漫长的流程&#xff0c;不断克服困难&#xff0c;不断反思前进的过程。在这个过程中…

机器学习:通俗理解马尔科夫随机场(MRF)及其应用(附例题)

目录0 写在前面1 无向概率图2 马尔科夫随机场3 马尔科夫独立性4 例题分析0 写在前面 机器学习强基计划聚焦深度和广度&#xff0c;加深对机器学习模型的理解与应用。“深”在详细推导算法模型背后的数学原理&#xff1b;“广”在分析多个机器学习模型&#xff1a;决策树、支持…

Git使用,在github中创建仓库

一.本地生成密钥&#xff1a; ssh-keygen //生成密钥 cat id_rsa.pub # 查看公钥 查看公钥&#xff0c;并将公钥添加到github的服务器上 二.创建文件&#xff0c;并且将文件上传到GitHub 设置全局用户信息&#xff1a; git config --global user.name dwerrwgit config…

LabVIEW NI数字万用表与开关握手扫描速率

LabVIEW NI数字万用表与开关握手扫描速率 在决定需要哪些设备来满足系统要求时&#xff0c;对扫描速率数据进行基准测试非常有用。数字万用表&#xff08;DMM&#xff09;和开关系统也是如此&#xff0c;因为扫描速率取决于数字万用表、开关和它们之间的触发器的速度。本文包含…

高并发系统设计 -- 抢红包设计

抢红包的业务分析 可以明显的看到打开了红包不一定可以抢到。这样做的好处是&#xff1a; 符合现实生活逻辑&#xff0c;有仪式感防止误领&#xff0c;发现不对劲可以马上退出流程拆的长一些&#xff0c;平摊高并发下的压力 预拆包&#xff1a;我在发红包的时候&#xff0c;就…

ansible的静态清单配置文件

清单文件 定义主机清单文件 清单中定义ansible将要管理的一批主机&#xff0c;这些主机也可以分配到组中&#xff0c;以进行集中管理。组中也可以包含子组&#xff0c;一台主机也可以是多个组中的成员。清单还可以设置应用到它所定义的主机和组的变量。 编写主机清单文件 主机…

归置归置,我的 2022

J3code杂文&#xff08;程序人生 # 年终总结&#xff09; 记得 2021 年我没有进行年终总结&#xff0c;也就没有发出过相关的内容出来。总结原因就是一个&#xff0c;躺平了&#xff0c;自毕业换工作之后&#xff0c;就一直在适应工作环境与生活环境中默默的度过了 2021 年。 …

你真的懂树吗?二叉树、AVL平衡二叉树、伸展树、B-树和B+树原理和实现代码详解...

树&#xff08;Tree&#xff09;是一种相当灵活的数据结构&#xff08;上一节已经详细讲解了基本的数据结构&#xff1a;线性表、栈和队列&#xff09;&#xff0c;你可能接触过二叉树&#xff0c;但是树的使用并不限于此&#xff0c;从简单的使用二叉树进行数据排序&#xff0…

(深度学习快速入门)第三章第一节:多层感知器简介

文章目录一&#xff1a;引入二&#xff1a;定义三&#xff1a;反向传播算法四&#xff1a;构建多层感知器完成波士顿房价预测一&#xff1a;引入 前文所讲到的波士顿房价预测案例中&#xff0c;涉及到的仅仅是一个非常简单的神经网络&#xff0c;它只含有输入层和输出层 但观…

vue3 antd项目实战——Form表单的重置与清空【resetFields重置表单未生效(手写重置函数)】

vue3 antd项目实战——resetFields重置表单无效【手写重置函数重置表单数据】关于form表单的文章合集场景复现原因分析解决方案(手写清空函数)关于form表单的文章合集 文章内容文章链接Form表单提交和校验https://blog.csdn.net/XSL_HR/article/details/128495087?spm1001.20…

面向对象定义一个hero类

问题定义一个hero类&#xff0c;属性有power&#xff0c;name&#xff0c;分别代表体力值和英雄的名字&#xff0c;体力值默认为100&#xff1b;方法有&#xff1a;1.行走的方法如果体力值为0&#xff0c;则输出不能行走&#xff0c;此英雌已死亡的信息&#xff1b;2.吃的方法&…

双非二本、已获HCIA认证的大二学生与C站相遇的2022

目录 前言 2022年1月、2月——迷茫 2022年3月~6月——调整规划 ​2022年7月——在CSDN发布第一篇博客 2022年8月——步入正轨&#xff0c;获得2022谷歌开发者大会入场名额 2022年9月~10月——开学季&#xff0c;收获季 2022年11月——第一次接触项目并去公司学习实践&…