【C++】位图与布隆过滤器(内含相关高频面试题)

news2025/5/20 6:17:32

 

  本篇文章会对位图和布隆过滤器进行详解。同时还会给出位图和布隆过滤器相关的高频面试题与解答。希望本篇文章会对你有所帮助。 

文章目录

一、位图的引入 

1、1 查找整数(腾讯面试题)

1、2 解决方法1

1、3 解决方法2 

 1、3、1 外部排序

二、位图的原理与实现

2、1 位图的概念

2、2 位图的实现

2、2、1 位图的框架

2、2、2 位图的实现细节 

三、布隆过滤器

3、1 布隆过滤器的概念

3、2 布隆过滤器的原理

3、3 布隆过滤器不支持删除

3、4 布隆过滤器的模拟实现

四、位图与布隆过滤器的总结

五、位图与布隆过滤器应用与拓展(高频面试题)

5、1 位图

 5、2 布隆过滤器


🙋‍♂️ 作者:@Ggggggtm 🙋‍♂️

👀 专栏:C++、数据结构 👀

💥 标题:位图与布隆过滤器💥

❣️ 寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景 ❣️ 

一、位图的引入 

1、1 查找整数(腾讯面试题)

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

1、2 解决方法1

  刚看到这个题目,第一感觉不就是查找数据是否存在吗!直接用二叉搜索树(set)或者哈希。但是我们不要忽略的所给的数据量。40亿的无符号整数大约占多少空间呢?1GB=1024MB=1024*1024KB=1024*1024*1024byte,也就是1GB大约是2^30字节(大约是10亿字节)。40亿个不重复的无符号整数就是160亿字节。只存储40亿个不重复的无符号整数所需要的空间大约就需要16GB,内存是存不下这么多数据的。更何况我们只是用了数组存储,那要是搜索树或者哈希呢?所需空间只会更大。所以这个方法是行不通的

1、3 解决方法2 

  还有人想到:排序(O(NlogN)),利用二分查找: logN 。如果要进行排序,首先数据肯定是放在磁盘上的。放在磁盘上的数据我们只能采用外部排序。什么是外部排序呢?

 1、3、1 外部排序

  在磁盘上对数据进行排序可以使用外部排序(External Sort)算法外部排序是一种处理大量数据的排序算法,适用于无法将所有数据同时加载到内存中的情况

  外部排序的基本思路是将待排序的数据分成若干个能够同时加载到内存中的块,并对每个块内的数据进行排序。然后使用归并排序(Merge Sort)等方法将排序好的块再合并起来,直到最终得到完整的有序数据集。

下面是一个基本的外部排序的步骤:

  1. 将待排序的数据分割成多个大小适合内存加载的块。
  2. 对每个块内的数据进行排序,可以选择合适的排序算法,如快速排序(Quick Sort)或堆排序(Heap Sort)等。
  3. 将排序好的块写回磁盘,并依次读取每个块的第一个元素到内存中。
  4. 将内存中的元素进行归并排序,选取最小的元素写入输出文件,并从所属块中读取下一个元素补充内存。
  5. 重复第4步,直到所有块都被读取完毕并排序完成。
  6. 合并的过程可能会产生新的块,如果超出内存限制,则需要划分新的块进行合并,直到最终得到完整的有序数据集。

  需要注意的是,在进行外部排序时,会产生大量的磁盘读写操作,所以效率相对较低。但是,由于数据无法一次性加载到内存中进行排序,外部排序是一种有效的处理大规模数据的排序方法。

  由于外部排序效率太慢的原因,这个方法似乎也不太合适

这里我们就要引入我们今天所讲解的内容:位图。利用位图可以很好的解决此问题

二、位图的原理与实现

2、1 位图的概念

  位图是一种用来表示某个特定范围内元素的存在与否的数据结构。它通常使用一个bit数组来表示,其中每个bit位代表一个元素的状态,0表示不存在,1表示存在。通过改变数组中的bit位,我们可以快速地进行元素的插入、删除和查询操作。具体我们可结合下图理解:

  如上图我们就可以很好的利用bit位来存储对应的数据了。

  位图的优点在于空间利用率高。假设要表示的元素范围是n个,那么只需要n个bit位,相当于n/8个字节即可。因此,在内存使用上非常高效。位图主要适用于处理大量的布尔类型信息,例如集合运算、去重判断或者判断某个数据存不存在等。

  利用位图来存储40亿个不重复的无符号整数需要开多大的空间呢?40亿字节大约是4GB,而我们所用到的一个字节可以存储8个bit位,也就是可以存储8个数据。那么总体下来大约是500MB的空间就可以!

2、2 位图的实现

2、2、1 位图的框架

  首先,位图所需要开的空间是我们根据我们所传入的数据个数进行开辟的。那我们就可以搭出来一个大概的框架了。代码如下:

	template<size_t N>
	class bitset
	{
	public:
		bitset()
		{
            //初始化空间
			_bs.resize(N / 8 + 1,0);
		}

		void set(size_t n)
		{
            //将对应元素n所在的比特位设置为1。
		}

		void reset(size_t n)
		{
            //将对应元素所在的比特位设置为0。
		}

		bool test(size_t n)
		{
            //通过查看对应元素所在的比特位,判断其是否为1
		}
	private:
		vector<char> _bs;
	};

2、2、2 位图的实现细节 

  通过上述的框架,我们也能大概知道位图的具体实现细节:

  • 创建位图:需要确定位图的大小,以便能够表示集合的所有元素。一般使用一个数组来表示位图,数组的每个元素可以存储多个比特位。根据集合的大小,确定所需的数组大小,并进行初始化。
  • 添加元素:将对应元素所在的比特位设置为1。
  • 删除元素:将对应元素所在的比特位设置为0。
  • 判断元素是否存在:通过查看对应元素所在的比特位,判断其是否为1。

  添加元素、删除元素和判断元素首先就是应该找到该元素所在的bit位。查找的方法如下图:

  当我们找到该元素后,再对其进行操作。我们要添加的话,就要把该位置的bit为设置成1。这是我们可使用按位或(‘ | ’)。只需要按或该bit位为1,且其他bit位为0的一个值就行了。具体代码如下:

		void set(size_t n)
		{
			int i = n / 8;
			int j = n % 8;
			_bs[i] |= (1 << j);
		}

  删除该元素, 就要把该位置的bit为设置成0。与按位或相反,我们需要使用按位与(‘ & ’)。具体的操作是:按或与该bit位为0,且其他bit位为1的一个值。具体代码如下:

		void reset(size_t n)
		{
			int i = n / 8;
			int j = n % 8;
			_bs[i] &= ~(1 << j);
		}

  判断该元素是否存在,我们只需要找到对应的bit位后,判断该bit位的值是否为1就行。与添加的思路与操作大致相同,我们直接看代码:

		bool test(size_t n)
		{
			int i = n / 8;
			int j = n % 8;

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

三、布隆过滤器

  我们发现上述的位图只能处理整数。那要是有同样数据的字符串呢?很显然,上述的位图并不能很好的解决问题。这里我们引入布隆过滤器。

  当然,用哈希表去存储大量的字符串也不行的,内存根本本存储不下的。那有没有什么方法让位图能够存储字符串呢?或者建立映射关系也不错!布隆过滤器就很好的使用映射这一点。

3、1 布隆过滤器的概念

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

3、2 布隆过滤器的原理

  布隆过滤器的核心思想是将元素经过多个字符串哈希函数的映射得到多个哈希值,并在位向量中将对应位置的bit位设置为1

  我们知道是通过特定的 字符串哈希函数的映射到对应的bit位置,但是那会不会不同的字符串映射到了相同的位置呢?答案是有可能的!举例如下图:

  我们假设上述的字符串:”HelloWorld“和”gtm“映射到了同一bit位上,会造成什么后果呢?同时又该怎么处理呢?

  当我们查找特定字符串是否存在的时候,会不会出现如下情况:我们已经在字符串”HelloWorld“的bit位置设置成了1。但是我们并没有也不需要设置字符串”gtm“,同时又对字符串”gtm“检测查找,那这时我们并没有存储字符串”gtm“,但是查找的时候依然会存在。简单来说,当有两个字符串可以映射到同一位置时,查找就会有可能出错

  那怎么解决呢?没有办法根本解决。一个字符串只能通过多个字符串哈希函数映射多个值来减少不同字符串映射到同一位置上的情况。可结合下图理解:

  也就是通过不同的字符串哈希函数映射到多个位置。两个不同的字符串同时映射到相同的三个位置概率很小。当我们检测查找时,需要通过三个值来判断。如果所有位置的bit位都为1,表示元素可能存在。当然这种情况也会存在误判,只不过是概率很小。

  我们想一下:判断存在时,可能会有误。那要是判断不存在呢?判断不存在的情况是不会出现错误的。为什么呢?如果判断是bit位为0,那就毫无疑问就是不存在。有人说不是不同字符串映射到同一位置吗?对啊,是能映射到同一位置。但是与检测存在又有什么关系呢?bit位为0,该bit位就没有字符串映射到此位置,就是不存在。

  布隆过滤器的一个重要特性是其会产生误判。由于多个元素可能映射到相同的位位置,查询一个元素时可能会得到错误的结果。误判率取决于哈希函数的数量、位数组的大小和插入的元素数量等因素。可以通过调整这些参数来控制误判率,在满足应用需求的前提下尽量减少误判。实例如下图:

3、3 布隆过滤器不支持删除

  我们知道位图支持删除操作,就是reset。那布隆过滤器呢?如果不支持删除原因又是什么呢?

  通过上述的布隆过滤器原理,我们知道为了减小不同字符串映射到同一位置上,我们采用了一个字符串采用多个字符串哈希函数进行映射多个值。假设出现如下情况:

  字符串“C++”和“HelloWorld”其中有一个值映射到了同一bit位上。因为我们删除某一字符串是删除其所有映射的bit位。同时查找也是需要同时满足所有映射的之都为1。我们对其中任意一个字符串删除,都会影响到另一个字符串

  一种支持删除的方法:将布隆过滤器中的每个比特位扩展成一个小的计数器,插入元素时给k个计数器(k个哈希函数计算出的哈希地址)加一,删除元素时,给k个计数器减一,通过多占用几倍存储空间的代价来增加删除操作。

  虽然这样可以支持删除操作,但是需要耗费大量空间。同时也会引入相应的问题:无法确认元素是否真正在布隆过滤器中和存在计数回绕。所以在实际中也并不实用。

3、4 布隆过滤器的模拟实现

  根据我们上述所描述的原理,其实我们大概也清楚了布隆过滤器的实现原理就是字符串哈希+位图。我们看如下实现代码:

	// 三个字符串哈希映射函数
    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 = 5;
		std::bitset<_ratio* N>* _bits = new std::bitset<_ratio* N>;
	};

  字符串哈希映射函数是通过实验和数据证明的,想要了解的可以查询资料。我们看到上述代码并不复杂,重在思想。其中Set时还需要进行除余,是为了防止越界。

四、位图与布隆过滤器的总结

  位图和布隆过滤器是在计算机科学中常用的数据结构,它们分别具有不同的优点和缺点。

位图的优点:

  1. 空间效率高:位图使用的是位运算,在表示大量数据时,相比于传统的数组或哈希表等数据结构,可以极大地减少所需的存储空间。
  2. 快速查询:由于位图只使用了0和1两种状态来表示数据的存在与否,所以查询某个元素是否存在非常快速,只需要进行简单的位运算即可。
  3. 支持高效操作:位图支持对多个位进行操作,如并、交、差等集合操作,可以高效地实现一些复杂的数据处理需求。

位图的缺点:

  1. 空间消耗:位图需要按位来存储数据,如果要表示的数据规模较大,会占用较多的内存空间。尤其是当数据不是稀疏分布时(位图所开辟的空间是根据数据的大小来开,而不是个数),并且数据范围很大时,位图会占用大量内存。
  2. 相对局限:只能处理整型。

布隆过滤器的优点:

  1. 空间效率高:布隆过滤器使用位数组和哈希函数来表示数据的存在与否,相比于传统的数据结构可以显著降低内存占用。
  2. 查询速度快:布隆过滤器在判断一个元素是否存在时,只需要经过一次哈希运算,可以快速地得出结果。
  3. 支持高吞吐量:布隆过滤器可以处理大规模的数据集合,并且具有较高的查询效率。

布隆过滤器的缺点:

  1. 容错性有限:由于布隆过滤器使用哈希函数来判断元素的存在与否,存在一定的哈希碰撞概率,这可能导致误判。即使一个元素不在布隆过滤器中,也有可能被误认为存在。
  2. 无法删除元素:一旦一个元素被加入到布隆过滤器中,就无法删除。因为删除一个元素需要改变数组中的值,可能影响到其他元素的判断结果。
  3. 只能对元素进行查找判断,不能很好的获取元素本身。

  综上所述,位图和布隆过滤器在空间效率和查询速度上都具有优势,但位图更适用于静态或只读的数据集合,而布隆过滤器适用于需要高吞吐量并可以容忍一定误判的场景。

五、位图与布隆过滤器应用与拓展(高频面试题)

5、1 位图

  给定100亿个整数,设计算法找到只出现一次的整数?

  首先100亿个整数,常用的查找方法:哈希、搜索树、排序+二分都是不行的。文章开始有解释。但是这里是要查找只出现一次的整数。

  一个位图只能表示存在或者不存在,但是并不能很好的记录次数。那要是两个位图呢?

  具体解决思路如下:

  1. 确定整数范围:首先确定整数的范围,假设范围为0到2^32-1,即32位无符号整数。

  2. 创建位图:根据确定的整数范围,创建一个长度为2^32的位图。每个位都初始化为0。

  3. 遍历整数列表:遍历一百亿个整数的列表,对于每个整数:

    • 检查该整数在两个位图中对应的位置上的值:
      • 如果该位置的值为00,将其置为01。
      • 如果该位置的值为10,则说明该整数已经出现过两次或更多次,表示重复出现。则不用处理。
  4. 再次遍历整数列表:再次遍历一百亿个整数的列表,对于每个整数:

    • 检查该整数在位图中对应的位置上的值:
      • 如果该位置的两个位图结合值为01,那么该整数只出现了一次,将其作为结果返回。

  这样就可以很好的统计次数了。具体可结合如下代码理解:

	template<size_t N>
	class twobitset
	{
	public:
		void set(size_t n)
		{
			//00
			if (_bs1.test(n) == false && _bs2.test(n) == false)
			{
				//01
				_bs2.set(n);
			}
			else if (_bs1.test(n) == false && _bs2.test(n) == true)  //01
			{
				//10
				_bs1.set(n);
				_bs2.reset(n);
			}
            // 10表示两次及以上,不同过多处理
		}

		void print_only_one()
		{
			for (int i = 0; i < N; i++)
			{
				if (_bs1.test(i) == false && _bs2.test(i) == true)
				{
					cout << i << endl;
				}
			}
		}
	private:
		bitset<N> _bs1;
		bitset<N> _bs2;
	};

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

  如果我们只有1GB的内存,但是需要在两个拥有100亿个整数的文件中找到交集,我们可以使用位图(Bitmap)的方法来解决。以下是使用位图的一种可能的解决方案:

  1. 创建位图:首先,创建位图,每个位图的大小都能够容纳100亿个整数的范围。假设每个整数都可以用一个bit表示,那么每个位图需要的内存大小为(10^9 * 8) bits = 1GB。

  2. 遍历第一个文件:逐个读取第一个文件中的整数,并将对应整数的位图位置为1,表示该整数存在。

  3. 遍历第二个文件并查找交集:逐个读取第二个文件中的整数,并检查对应整数在第一个位图中是否为1。如果是,则表示这个整数是两个文件的交集之一。

  4. 输出交集结果:根据需要,可以将找到的交集整数输出到文件或进行其他操作。

  使用位图的方法可以显著减少内存使用量。但是需要注意的是,该方法的前提是整数的范围是已知的,并且可以用位图来表示。此外,由于需要逐个读取并处理整数,因此仍然可能需要较长时间来完成整个过程。

  位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整 数。

  这个问题的思路与第一个问题的思路一摸一样。只不过是多了统计2次(2次以上均用11来表示)以上的情况。具体不再过多解释。 

 5、2 布隆过滤器

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

  注意,query就不是整数了,就不能再使用位图了。近似算法可使用布隆过滤器,那精确算法呢?精确算法采用的哈希切分的方式。具体方法如下:

 上图的主要思路就是:把大文件切分成多个小文件。在把两个编号相同的小文件依次加载到内存进行查找交集。注意:并不是均匀切分,因为我们也不知道query到底是什么,映射后进入那个文件。 如果映射后的两个小文件数据量仍然过大,那么就继续分割。

  近似算法的思想是通过牺牲一定的准确性来换取更小的内存占用。常见的近似算法是Bloom Filter(布隆过滤器)。Bloom Filter是一种用于快速检索一个元素是否属于某个集合的概率型数据结构。具体操作如下:

  • 创建一个长度为M的位数组,并初始化所有位为0。
  • 使用K个不同的哈希函数。对于每个query,在K个哈希函数的作用下得到K个哈希值。
  • 将位数组中对应的位置设为1。这样,第一个文件的query就被映射到了位数组上。
  • 对于第二个文件的每个query,同样进行哈希操作,然后判断位数组对应的位置是否全部为1。如果是,则将该query添加到结果集合中。

  近似算法的准确性取决于哈希函数的选择和位数组的大小。通过调整参数,可以控制误判率的大小,从而在所需内存较小的情况下找到交集。但由于牺牲了准确性,可能会有一些误判。

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

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

  这个题的思路与上一题的思路大致相同。都是采用了哈希切分的方法。切分成多个小文件,再一次加载到内存中。

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

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

相关文章

电压调整器之LDO稳压器电路 士兰微SA1117B系列SA1117BH-ADJTR

关于LDO调节器&#xff08;Low Dropout Regulator&#xff09;是一种电压稳压器件&#xff0c;常用于电子设备中&#xff0c;用于将高电压转换为稳定的低电压。它能够在输入电压和输出电压之间产生较小的差异电压&#xff0c;因此被称为"低压差稳压器"。 LDO调节器通…

Llama 2免费托管及API提供

Llama 2 是 Meta 最新的文本生成模型&#xff0c;目前其性能优于所有开源替代方案。 推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 1、强大的Llama 2 它击败了 Falcon-40B&#xff08;之前最好的开源基础模型&#xff09;&#xff0c;与 GPT-3.5 相当&#xff0c;仅低…

禁止特斯拉入内 — 智能驾驶引发的“争议”与“合规”之路

近日&#xff0c;湖南岳阳三荷机场停车场禁止特斯拉入内引发关注&#xff0c;原因在于车主离开车辆后&#xff0c;特斯拉自带的哨兵模式会对车身周边环境进行录像。实际上&#xff0c;之前就有网友提到军事禁区、党政机关、重点政府单位、重点国有企业等也是不允许特斯拉进入。…

电商增强现实3D模型优化需要关注的4个方面

到目前为止&#xff0c;AR技术已经发展到足以在更广泛的范围内实施。 在电子商务中&#xff0c;这项技术有望提供更令人兴奋的购物体验。 为了实现这一目标&#xff0c;在这篇博客中&#xff0c;我将介绍如何针对电子商务中的 AR 优化 3D 模型。 推荐&#xff1a;用 NSDT编辑器…

【hadoop】windows上hadoop环境的搭建步骤

文章目录 前言基础环境下载hadoop安装包下载hadoop在windows中的依赖配置环境变量 Hadoop hdfs搭建创建hadfs数据目录修改JAVA依赖修改配置文件初始化hdfs namenode启动hdfs 前言 在大数据开发领域中&#xff0c;不得不说说传统经典的hadoop基础计算框架。一般我们都会将hadoo…

LeetCode 160.相交链表

文章目录 &#x1f4a1;题目分析&#x1f4a1;解题思路&#x1f6a9;步骤一&#xff1a;找尾节点&#x1f6a9;步骤二&#xff1a;判断尾节点是否相等&#x1f6a9;步骤三&#xff1a;找交点&#x1f344;思路1&#x1f344;思路2 &#x1f514;接口源码 题目链接&#x1f449;…

九五从零开始的运维之路(其三十五)

文章目录 前言一、概述1.概念2.组成3.特点4.工作原理5.优点&#xff1a; 二、各节点及其ip地址三、构建MHA1.ssh免密登录2.构建mysql主从复制&#xff08;一&#xff09;安装mariadb数据库并启动&#xff08;二&#xff09;master服务器&#xff08;三&#xff09;slave服务器&…

【Java转Go】快速上手学习笔记(二)之基础篇一

目录 创建项目数据类型变量常量类型转换计数器键盘交互流程控制代码运算符 创建项目 上篇我们安装好了Go环境&#xff0c;和用IDEA安装Go插件来开发Go项目&#xff1a;【Java转Go】快速上手学习笔记&#xff08;一&#xff09;之环境安装篇 。 这篇我们开始正式学习Go语言。我…

【数据结构OJ题】链表中倒数第k个结点

原题链接&#xff1a;https://www.nowcoder.com/practice/529d3ae5a407492994ad2a246518148a?tpId13&&tqId11167&rp2&ru/activity/oj&qru/ta/coding-interviews/question-ranking 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 …

数据结构的树存储结构

数据结构的树存储结构 之前介绍的所有的数据结构都是线性存储结构。本章所介绍的树结构是一种非线性存储结构&#xff0c;存储的是具有“一对多”关系的数据元素的集合。 (A) (B) 图 1 树的示例 图 …

vue树状结构以及设计思路

设计思路&#xff1a;多级数组循环遍历&#xff0c;第一层样式加三角形折叠&#xff0c;第二层在文字前方加 —&#xff08;横线&#xff09;&#xff0c;第三层加横线&#xff0c;第四层加点。给第二层第三层左侧加左边框&#xff0c;用translateY进行位移就形成了树状样式。 …

《起风了》C++源代码

使用方法 Visual Studio、Dev-C、Visual Studio Code等C/C创建一个 .cpp 文件&#xff0c;直接粘贴赋值即可。 #include <iostream> #include <Windows.h> #pragma comment(lib,"winmm.lib") using namespace std; enum Scale {Rest 0, C8 108, B7 …

SpringBoot08——前端数据模拟MockJS+vue-element-admin后台集成

感觉用到再说吧 2. vue-element-admin后台集成 3.JWT跨域认证 看自己的demo2源码吧

好用的networkx绘图包

1. NetworkX简介 NetworkX 是一个用于创建、操作和研究复杂网络的 Python 库。它可以创建、分析和可视化各种类型的网络(包括有向图和无向图)&#xff0c;例如社交网络、Web图、生物网络等。 NetworkX 提供了许多图的算法和分析工具&#xff0c;比如节点的度、网络的直径、最短…

jvm内存溢出排查(使用idea自带的内存泄漏分析工具)

文章目录 1.确保生成内存溢出文件2.使用idea自带的内存泄漏分析工具3.具体实验一下 1.确保生成内存溢出文件 想分析堆内存溢出&#xff0c;一定在运行jar包时就写上参数-XX:HeapDumpOnOutOfMemoryError&#xff0c;可以看我之前关于如何运行jar包的文章。若你没有写。可以写上…

express学习笔记8 - 文件上传 下载以及预览

一、上传 1、 安装multer (任意选其中一种) yarn add multer --S npm install multer --S 2、新建配置文件(utils/multerConfig) const multer require(multer); const mkdirp require(mkdirp); // const sd require(silly-datetime); const path require(path);con…

什么叫加杠杆投资_个人炒股如何加杠杆

加杠杆投资是指通过借款或者杠杆交易的方式&#xff0c;以较小的自有资金控制较大的资金进行投资。在加杠杆的情况下&#xff0c;投资者可以获得更高的投资回报&#xff0c;但同时也面临较高的风险。 个人炒股加杠杆可以通过以下几种方式实现&#xff1a; 1. 股票配资&#x…

GT Code - 图译算法编辑器(集成QT、C++、C、Linux、Git、java、web、go、高并发、服务器、分布式、网络编程、云计算、大数据项目)

目录 项目概述 发文意义 项目介绍 功能分析 设计概要 功能展示 项目文档 项目概述 “GT Code 图译算法编辑器”是一款跨平台、轻量级的代码编辑器&#xff0c;主要面向软件开发人员&#xff0c;它实现了编辑、编译、绘制代码流程图、生成调试演示动画等功能&#xff0c;以…

透过源码理解Flutter中widget、state和element的关系

1、framework源码组成 Flutter中widget、state、element的源码位于framework.dart中&#xff0c;整个文件6693行(版本Flutter 3.12.0-14.0.pre.28)。整个代码可划分为若干部分&#xff0c;主要包括key、widget、state、element四部分。 1.1 key 关于key的代码65行到272行&am…

STM32存储左右互搏 I2C总线FATS读写EEPROM ZD24C1MA

STM32存储左右互搏 I2C总线FATS读写EEPROM ZD24C1MA 在较低容量存储领域&#xff0c;EEPROM是常用的存储介质&#xff0c;可以通过直接或者文件操作方式进行读写。不同容量的EEPROM的地址对应位数不同&#xff0c;在发送字节的格式上有所区别。EEPROM是非快速访问存储&#xf…