【C++】位图 | 布隆过滤器

news2024/9/29 1:20:27

​🌠 作者:@阿亮joy.
🎆专栏:《吃透西嘎嘎》
🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根
在这里插入图片描述

目录

    • 👉哈希函数👈
    • 👉位图👈
      • 位图概念
      • 位图的实现
      • 位图的应用
    • 👉布隆过滤器👈
      • 布隆过滤器的提出
      • 布隆过滤器概念
      • 布隆过滤器的实现
        • 1. 查找
        • 2. 删除
      • 布隆过滤器优点和缺点
    • 👉总结👈

👉哈希函数👈

引起哈希冲突的一个原因可能是:哈希函数设计不够合理。
哈希函数的设计原则

  • 哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有 m 个地址时,其值域必须在 0 到 m-1 之间
  • 哈希函数计算出来的地址能均匀分布在整个空间中
  • 哈希函数应该比较简单

常见哈希函数

  1. 直接定址法(常用)
    取关键字的某个线性函数为散列地址:Hash(Key) = A * Key + B
    优点:简单、均匀且不存在哈希冲突
    缺点:需要事先知道关键字的分布情况
    使用场景:适合查找比较小且连续的情况

    面试题:字符串中第一个只出现一次字符
  2. 除留余数法(常用)
    设散列表中允许的地址数为 m,取一个不大于 m,但最接近或者等于 m 的质数 p 作为除数,按照哈希函数:Hash(key) = key% p(p <= m),将关键码转换成哈希地址。除留余数法存在哈希冲突,重点解决哈希冲突。
  3. 平方取中法(了解)
    假设关键字为 1234,对它平方就是 1522756,抽取中间的 3 位 227 作为哈希地址;再比如关键字为 4321,对它平方就是 18671041,抽取中间的 3 位 671 (或710)作为哈希地址。平方取中法比较适合:不知道关键字的分布,而位数又不是很大的情况。
  4. 折叠法是将关键字从左到右分割成位数相等的几部分(最后一部分位数可以短些),然后将这几部分叠加求和,并按散列表表长,取后几位作为散列地址。折叠法适合事先不需要知道关键字的分布,适合关键字位数比较多的情况,只适用于整数。

在这里插入图片描述
5. 随机数法(了解)
选择一个随机函数,取关键字的随机函数值为它的哈希地址,即 H(key) = random(key),其中 random 为随机数函数。通常应用于关键字长度不等时采用此法。
6. 数学分析法(了解)
设有 n 个 d 位数,每一位可能有 r 种不同的符号,这 r 种不同的符号在各位上出现的频率不一定相同,可能在某些位上分布比较均匀,每种符号出现的机会均等,在某些位上分布不均匀只有某几种符号经常出现。可根据散列表的大小,选择其中各种符号分布均匀的若干位作为散列地址。数字分析法通常适合处理关键字位数比较大的情况,如果事先知道关键字的分布且关键字的若干位分布较均匀的情况。例如:

在这里插入图片描述
假设要存储某家公司员工登记表,如果用手机号作为关键字,那么极有可能前 7 位都是相同的,那么我们可以选择后面的四位作为散列地址,如果这样的抽取工作还容易出现 冲突,还可以对抽取出来的数字进行反转(如 1234 改成 4321 )、右环位移(如 1234 改成 4123 )、左环移位、前两数与后两数叠加(如 1234 改成 12+34=46 )等方法。

注意:哈希函数设计的越精妙,产生哈希冲突的可能性就越低,但是无法避免哈希冲突。

👉位图👈

位图概念

  1. 面试题
    给 40 亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这 40 亿个数中。
  • 遍历,时间复杂度O(N)
  • 排序(O(NlogN)),利用二分查找: logN
  • 位图解决
    数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态。那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为 1,代表存在,为 0代表不存在。比如:

在这里插入图片描述
在这里插入图片描述
2. 位图概念
所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的。注意:位图所开空间要大于或等于整型的范围,因为有可能有些数字数,有些数字小。

位图的实现

位图最核心的三个节点是setresettestset是将 x 对应的比特位设置为 1,reset是将 x 对应的比特位设置为 0,test是查看 x 在不在。

在这里插入图片描述

#pragma once

namespace Joy
{
	template<size_t N>
	class bitset
	{
	public:
		bitset()
		{
			_bits.resize(N / 8 + 1, 0);	// 多开一个字节,防止越界
		}

		// 将比特位设置为1
		void set(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;

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

		// 将比特位设置为0
		void reset(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;

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

		// 查x在不在
		bool test(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;

			return (_bits[i] & (1 << j));
		}
	
	private:
		vector<char> _bits;
	};

	void BitSetTest()
	{
		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;
	}

	void BitSetTest2()
	{
		// 开出42亿9千万个比特位
		bitset<-1> bs1;	
		bitset<0xffffffff> bs2;
	}
}

在这里插入图片描述
在这里插入图片描述

位图的应用

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

题目一:给定 100 亿个整数,设计算法找到只出现一次的整数? 这种题目是 KV 的统计次数搜索模型,一个数字出现次数有三种情况:出现零次、出现一次以及出现两次及以上,这三种情况只需要用两个比特位就可以表示。

在这里插入图片描述

	template <size_t N>
	class twobitset
	{
	public:
		void set(size_t x)
		{
			bool inset1 = _bs1.test(x);
			bool inset2 = _bs2.test(x);

			// 00
			if(inset1 == false && inset2 == false)
			{
				// -> 01
				_bs2.set(x);
			}
			else if (inset1 == false && inset2 == true)	// 01
			{
				// -> 10
				_bs1.set(x);
				_bs2.reset(x);
			}
			else if (inset1 == true && inset2 == false)
			{
				// -> 11
				_bs2.set(x);
			}
			// else是x出现三次及三次以上

		}

		void print_once_num()
		{
			for (size_t i = 0; i < N; ++i)
			{
				if (_bs1.test(i) == false && _bs2.test(i) == true)
					cout << i << " ";
			}
			cout << endl;
		}

	private:
		bitset<N> _bs1;
		bitset<N> _bs2;
	};

	void BitSetTest3()
	{
		int a[] = { 3, 4, 5, 2, 3, 4, 4, 4, 4, 12, 77, 65, 44, 4, 44, 99, 33, 33, 33, 6, 5, 34, 12 };
		twobitset<100> bs;
		for (auto e : a)
		{
			bs.set(e);
		}

		bs.print_once_num();
	}

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

注:位图只能处理整形。采用位图标记字符串时,必须先将字符串转化为整形的数字,找到位图中对应的比特 位,但是在字符串转整形的过程中,可能会出现不同字符串转化为同一个整形数字,即冲突,因此一般不会直接用位图处理字符串。

👉布隆过滤器👈

布隆过滤器的提出

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

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

布隆过滤器概念

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

在这里插入图片描述

布隆过滤器的实现

1. 查找

布隆过滤器的思想是将一个元素用多个哈希函数映射到一个位图中,因此被映射到的位置的比特位一定为 1。所以可以按照以下方式进行查找:分别计算每个哈希值对应的比特位置存储的是否为零,只要有一个为零,代表该元素一定不在哈希表中,否则可能在哈希表中注意:布隆过滤器如果说某个元素不存在时,该元素一定不存在,如果该元素存在时,该元素可能存在,因为有些哈希函数存在一定的误判。

在这里插入图片描述
在这里插入图片描述

布隆过滤器的应用场景

在这里插入图片描述

布隆过滤器拓展资料:链接 ,字符串哈希算法:链接。

布隆过滤器的公式

在这里插入图片描述

#pragma once
#include "BitSet.h"

namespace Joy
{
	// 哈希函数
	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
	{
		// AP
		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
	{
		// DJB
		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;	// _ratio为倍率
		bitset<_ratio* N> _bits;	// 使用自己实现的bitset
	};

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

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

		string arr2[] = { "苹果111", "西瓜", "阿里2222", "美团", "苹果dadcaddxadx", "字节", "西瓜sSSSX", "苹果 ", "香蕉", "苹果$", "腾讯" };

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

	void BloomFilterTest2()
	{
		srand(time(0));
		const size_t N = 1000000;
		BloomFilter<N> bf;
		cout << sizeof(bf) << endl;

		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;
	}
}

在这里插入图片描述

在这里插入图片描述

存储空间越大,布隆过滤器的误判率就会越低。注:库里的 bitset 是静态数组,空间太大容易栈溢出,可以在堆上开空间。

2. 删除

布隆过滤器不能直接支持删除工作,因为在删除一个元素时,可能会影响其他元素。
在这里插入图片描述
在这里插入图片描述
比如:删除上图中"tencent"元素,如果直接将该元素所对应的二进制比特位置0,“baidu”元素也被删除了,因为这两个元素在多个哈希函数计算出的比特位上刚好有重叠。

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

布隆过滤器优点和缺点

优点

  1. 增加和查询元素的时间复杂度为:O(K), (K 为哈希函数的个数,一般比较小),与数据量大小无关
  2. 哈希函数相互之间没有关系,方便硬件并行运算
  3. 布隆过滤器不需要存储元素本身,在某些对保密要求比较严格的场合有很大优势
  4. 在能够承受一定的误判时,布隆过滤器比其他数据结构有这很大的空间优势
  5. 数据量很大时,布隆过滤器可以表示全集,其他数据结构不能
  6. 使用同一组散列函数的布隆过滤器可以进行交、并、差运算

缺点

  1. 有误判率,即存在假阳性(False Position),即不能准确判断元素是否在集合中(补救方法:再建立一个白名单,存储可能会误判的数据)
  2. 不能获取元素本身
  3. 一般情况下不能从布隆过滤器中删除元素
  4. 如果采用计数方式删除,可能会存在计数回绕问题

布隆过滤器的题目

题目一:给两个文件,分别有 100 亿个 query,我们只有 1G 内存,如何找到两个文件交集?分别给出精确算法和近似算法。 query 是查询,常见的查询有:网络请求、SQL 语句等,它们都是字符串。近似算法允许一些误判,那么我们可以先将一个文件的 query 放入布隆过滤器中,再去查另一个文件的 query 在不在布隆过滤器中,就可以找到两个文件的交集了(还需要去重)。精确算法如下图所示:

在这里插入图片描述

题目二:如何扩展BloomFilter使得它支持删除元素的操作?布隆过滤器一般是不支持删除的,支持删除可能会影响其他值的查询。如果想要支持删除,可以添加引用计数。但是支持了删除,空间消耗就更多,优势就变小了。

哈希切分题目:给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址?与上题条件相同,如何找到top K的IP?如何直接用Linux系统命令实现?

在这里插入图片描述

Linux 系统命令实现

在这里插入图片描述

在这里插入图片描述

注:哈希切分并不是平均切分,而是相同的哈希值的字符串等进入到相同的位置。

哈希的应用非常地广泛,服务器存储中也使用到了哈希。

在这里插入图片描述

👉总结👈

本篇博客主要讲解了常见的哈希函数,什么是位图、位图的实现和应用、什么是布隆过滤器、布隆过滤器的实现和优缺点以及哈希切分等等。那么以上就是本篇博客的全部内容了,如果大家觉得有收获的话,可以点个三连支持一下!谢谢大家!💖💝❣️

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

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

相关文章

添加选课模块分析

1 模块需求分析 1.1 模块介绍 本模块实现了学生选课、下单支付、学习的整体流程。 网站的课程有免费和收费两种&#xff0c;对于免费课程学生选课后可直接学习&#xff0c;对于收费课程学生需要下单且支付成功方可选课、学习。 选课&#xff1a;是将课程加入我的课程表的过…

论文投稿指南——中文核心期刊推荐(水利工程)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

大展宏图、首创基于.NET 7强大内核-Zoomla!逐浪CMS v8.7.0发布

2022年底&#xff0c;微软 .NET Conf 在线活动正式开幕。作为微软开源、跨平台开发平台&#xff0c;.NET 7 现已推出首个正式版&#xff0c;这也代表微软的“统一工作”终于完成。 使用 .NET 7 可以轻松地将 .NET 7 项目容器化&#xff0c;在 GitHub 操作中设置 CI / CD 工作流…

拔高法三视图

拔高法最主要的就是俯视图&#xff0c;是三视图的根基&#xff0c;看主视图和侧视图&#xff0c;顶点位置在底面(俯视图)范围内&#xff0c;不在则不能拔高&#xff1b;俯视图有虚线不能拔高 首先标出俯视图所有结点&#xff0c;并且画出俯视图所对应的直观图。用斜二测画法 …

Spring Cloud 中的OpenFeign+Ribbon详解

1 spring cloud 远程调用没有看过的小伙伴可以点击传送门先去了解Nacos。有了Nacos做注册中心后&#xff0c;我们就可以获取其他服务的地址进行调用了。远程调用就需要用到我们今天的主角OpenFeign&#xff0c;如果被调用服务存在多个实例就需要进行负载均衡&#xff0c;负载均…

给定两个数组x和hp,长度都是N。 x数组一定是有序的,x[i]表示i号怪兽在x轴上的位置 hp数组不要求有序,hp[i]表示i号怪兽的血量

题目描述 给定两个数组x和hp&#xff0c;长度都是N。 x数组一定是有序的&#xff0c;x[i]表示i号怪兽在x轴上的位置 hp数组不要求有序&#xff0c;hp[i]表示i号怪兽的血量 为了方便起见&#xff0c;可以认为x数组和hp数组中没有负数。 再给定一个正数range&#xff0c;表示如果…

Vue 快速入门(二)

1、Vue浏览器插件安装 安装地址 https://devtools.vuejs.org/guide/installation.html下载完后&#xff0c;直接将vuejs-devtools.crx文件拖到Chrome浏览器扩展程序中去即可。如图&#xff1a; 2.安装完成后&#xff0c;试试效果&#xff0c;我们打开之前写的hello.html页面看…

32.Isaac教程--操纵运动规划

操纵运动规划 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html Isaac SDK 为机械臂的运动规划提供了以下组件&#xff1a; EndEffectorGlobalPlanner&#xff1a;使用逆运动学将末端执行器的笛卡尔目标转换为关节角度目标。 此小码可以接收笛卡尔…

云原生技能树-容器镜像制作、发布、拉取和运行

创建仓库 请在你自己的 gitcode.net 上创建一个仓库&#xff0c;命名为cloud_native_hello_py&#xff0c;目录结构如下&#xff1a; . ├── .dockerignore ├── .gitignore ├── Dockerfile ├── README.md └── src├── main.py└── requirements.txt其中 ma…

avb校验相关与块校验原理

一、启动校验流程 edk2/QcomModulePkg/Library/avb/VerifiedBoot.c DEBUG ((EFI_D_ERROR, "LoadImageAndAuth failed %r\n", Status)); in LoadImageAndAuth()edk2/QcomModulePkg/Application/LinuxLoader/LinuxLoader.c DEBUG ((EFI_D_ERROR, "LoadImageAndAu…

docker部署redis后,修改配置文件的requirepass后无效

解决方案 执行docker run命令时不要使用参数–requirepass docker部署redis流程&#xff08;问题复现&#xff09; 1. 启动redis容器 在服务器docker运行时&#xff0c;执行下列命令。&#xff08;会自动在远程仓库下载镜像&#xff09; redis: docker run \ --restartalw…

高等数学【合集】

文章目录极限计算求导计算极限计算 第一步:先看x→value确定类型第一步:先看x \rightarrow value确定类型第一步:先看x→value确定类型 7种未定型:∞∞,00,1∞,0∞,∞0,00,∞−∞7种未定型: \frac{\infty}{\infty},\frac{0}{0},1^{\infty},0^{\infty},\infty^0,0^0,\infty-\inf…

win10开机后桌面无图标问题解决办法

本篇文章主要讲解win10下桌面无图标的问题解决办法。 日期&#xff1a;2023年1月21日 作者&#xff1a;任聪聪 主要原因&#xff1a; 这个问题的原因是资源管理器或者注册表中有垃圾注册数据导致&#xff0c;实际上和显卡没有任何关系&#xff0c;但有些情况是由于驱动问题导致…

OSPF 特殊区域介绍、Stub、Totally Stub、NSSA、Totally NSSA

1.1.0 路由 OSPF 特殊区域介绍、Stub、Totally Stub、NSSA、Totally NSSA 特殊区域的产生和注意事项 产生&#xff1a;OSPF通过划分区域减小网络内路由器的LSDB的规模。对于那些位于AS边界的非骨干区域如果该设备是较为低端的路由器&#xff0c;则无法承受过多的路由条目。为此…

前端学习第一阶段:1-4章

学习总结&#xff1a;前四章学习总体来说不太难理解&#xff0c;如果时间宽裕&#xff0c;一天之内可以学完。 第一章 前端就业班课程导学 第二章 HTML5 CSS3课前导学 第三章 VSCode编辑器的使用 第四章 HTML 4-1 HTML初识 List item 01-基础班学习路线 List item 02-HTML简…

【Linux_】环境变量

【Linux_】环境变量 心有所向&#xff0c;日复一日&#xff0c;必有精进专栏&#xff1a;《Linux_》作者&#xff1a;沂沐沐目录 【Linux_】环境变量 什么是环境变量 常见变量 查看环境变量方法 环境变量相关的命令 通过系统调用获取或设置环境变量 环境变量通常是具有全…

代码随想录算法训练营第22天 二叉树 java :235. 二叉树的最近公共祖先 701.二叉搜索树中的插入操作 450.删除二叉搜索树中的节点

文章目录LeetCode 236. 二叉树的最近公共祖先题目讲解思路LeetCode 701.二叉搜索树中的插入操作题目讲解思路LeetCode 450.删除二叉搜索树中的节点题目讲解思路示图总结既然还是要生活&#xff0c;那么就学会主宰生活LeetCode 236. 二叉树的最近公共祖先 题目讲解 思路 求最小…

【数据结构与算法】详解二叉树以及模拟实现二叉树

文章目录前言:1.二叉树的定义2.二叉树的相关术语3.二叉树的性质4.特殊的二叉树5.二叉树的遍历前序遍历中序遍历后序遍历层序遍历6.获取树中节点的个数方法1:遍历思想方法2:子问题的思想7.获取叶子节点的个数方法1:遍历思想方法2:子问题的思想8.获取第K层节点的个数9.获取二叉树…

链表(LinkedList)

链表(LinkedList) 链表是有序的列表&#xff0c;但是其在内存的存储不一定连续 由这张图我们可以看出 链表是以节点的方式来存储的&#xff0c;是链式存储 每个节点包含data域&#xff0c;next域&#xff1a;指向下一个节点 我们可以发现链表的各个节点不一定是连续存储的 …

再见了HDMI Alt

点击上方“LiveVideoStack”关注我们▲扫描图中二维码或点击阅读原文▲了解音视频技术大会更多信息编者按&#xff1a;其实在未能推出配套线缆和适配器的那一刻&#xff0c;HDMI Alt模式就已经没有未来了。HDMI已全面落后DisplayPort。本文来自Arstechnica。文/Scharon Hardin…