【数据结构(C++版)】哈希表(散列表)

这篇具有很好参考价值的文章主要介绍了【数据结构(C++版)】哈希表(散列表)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录 

1. 散列表的概念

2. 散列函数的构造方法

2.1 直接定址法

2.2 除留余数法

2.3 数字分析法

2.4 平方取中法

3. 处理冲突的方法

3.1 开放定址法

3.1.1 线性探测法

3.1.2 平方探测法

3.1.3 双散列法

3.1.4 伪随机序列法

3.2 拉链法(链接法)

4. 散列查找及性能分析

5. 哈希的应用

5.1 位图

5.1.1 位图的概念

5.1.2 位图的实现

5.1.3 位图的应用

5.2 布隆过滤器

5.2.1 布隆过滤器的提出

5.2.2 布隆过滤器的概念

5.2.3 布隆过滤器的实现

5.2.4 布隆过滤器的应用


1. 散列表的概念

在线性表和树表的查找中,记录在表中的位置与记录的关键字之间不存在确定关系,因此,在这些表中查找记录时需进行一系列的关键字比较。这类查找方法建立在“比较”的基础上,查找的效率取决于比较的次数。

散列函数:一个把查找表中的关键字映射成该关键字对应的地址的函数,记为Hash(key) = Addr(这里的地址可以是数组下标、索引或内存地址等)。

散列函数可能会把两个或两个以上的不同关键字映射到同一地址,称这种情况为冲突,这些发生碰撞的不同关键字称为同义词。一方面,设计得好的散列函数应尽量减少这样的冲突;另一方面,由于这样的冲突总是不可避免的,所以还要设计好处理冲突的方法。

散列表:根据关键字而直接进行访问的数据结构。也就是说,散列表建立了关键字和存储地址之间的一种直接映射关系。

理想情况下,对散列表进行查找的时间复杂度为O(1),即与表中元素的个数无关。下面分别介绍常用的散列函数和处理冲突的方法。

2. 散列函数的构造方法

在构造散列函数时,必须注意以下几点:

  • 散列函数的定义域必须包含全部需要存储的关键字,而值域的范围则依赖于散列表的大小或地址范围。
  • 散列函数计算出来的地址应该能等概率、均匀地分布在整个地址空间中,从而减少冲突的发生。
  • 散列函数应尽量简单,能够在较短的时间内计算出任意一个关键字对应的散列地址。下面介绍常用的散列函数。

2.1 直接定址法

直接取关键字的某个线性函数值为散列地址,散列函数为

H(key) = key 或 H(key) = a * key + b

式中,a和b是常数。这种方法计算最简单,且不会产生冲突。它适合关键字的分布基本连续的情况,若关键字分布不连续,空位较多,则会造成存储空间的浪费。

2.2 除留余数法

这是一种最简单、最常用的方法,假定散列表表长为m,取一个不大于m但最接近或等于m的质数p,利用以下公式把关键字转换成散列地址。散列函数为

H(key) = key % p

除留余数法的关键是选好p,使得每个关键字通过该函数转换后等概率地映射到散列空间上的任意一个地址,从而尽可能减少冲突的可能性。

2.3 数字分析法

设关键字是r进制数(如十进制数),而r个数码在各位上出现的频率不一定相同,可能在某些位上分布均匀一些,每种数码出现的机会均等:而在某些位上分布不均匀,只有某几种数码经常出现,此时应选取数码分布较为均匀的若干位作为散列地址。这种方法适合于已知的关键字集合,若更换了关键字,则需要重新构造新的散列函数。

2.4 平方取中法

顾名思义,这种方法取关键字的平方值的中间几位作为散列地址。具体取多少位要视实际情况而定。这种方法得到的散列地址与关键字的每位都有关系,因此使得散列地址分布比较均匀,适用于关键字的每位取值都不够均匀或均小于散列地址所需的位数。

在不同的情况下,不同的散列函数具有不同的性能,因此不能笼统地说哪种散列函数最好。在实际选择中,采用何种构造散列函数的方法取决于关键字集合的情况,但目标是尽量降低产生冲突的可能性。

3. 处理冲突的方法

应该注意到,任何设计出来的散列函数都不可能绝对地避免冲突。为此,必须考虑在发生冲突时应该如何处理,即为产生冲突的关键字寻找下一个“空”的Hash地址。用Hi表示处理冲突中第i次探测得到的散列地址,假设得到的另一个散列地址H1仍然发生冲突,只得继续求下一个地址H2,以此类推,直到Hk不发生冲突为止,则Hk为关键字在表中的地址。

3.1 开放定址法

所谓开放定址法,是指可存放新表项的空闲地址既向它的同义词表项开放,又向它的非同义词表项开放。其数学递推公式为

Hi = (H(key) + di) % m

式中,H(key)为散列函数;i = 0,1,2,…,k(k≤m-1);m表示散列表表长;di为增量序列。

取定某一增量序列后,对应的处理方法就是确定的。通常有以下4种取法:

3.1.1 线性探测法

当di = 0,1,2,…,m-1时,称为线性探测法。这种方法的特点是:冲突发生时,顺序查看表中下一个单元(探测到表尾地址m-1时,下一个探测地址是表首地址0),直到找出一个空闲单元(当表未填满时一定能找到一个空闲单元)或查遍全表。线性探测法可能使第i个散列地址的同义词存入第i+1个散列地址,这样本应存入第i+1个散列地址的元素就争夺第i+2个散列地址的元素的地址……从而造成大量元素在相邻的散列地址上“聚集”(或堆积)起来,大大降低了查找效率。

3.1.2 平方探测法

当di = ,,,,,…,,时,称为平方探测法,其中k≤m/2,散列表长度m必须是一个可以表示成4k+3的素数,又称二次探测法。

平方探测法是一种处理冲突的较好方法,可以避免出现“堆积”问题,它的缺点是不能探测到散列表上的所有单元,但至少能探测到一半单元。

3.1.3 双散列法

当di = 时,称为双散列法。需要使用两个散列函数,当通过第一个散列函数H(key)得到的地址发生冲突时,则利用第二个散列函数计算该关键字的地址增量。它的具体散列函数形式如下:

Hi = (H(key) + i*) % m

初始探测位置H0 = H(key) % m。i是冲突的次数,初始为0。在双散列法中,最多经过m-1次探测就会遍历表中所有位置,回到H位置。

3.1.4 伪随机序列法

当di = 伪随机数序列时,称为伪随机序列法。

注意:在开放定址的情形下,不能随便物理删除表中的已有元素,因为若删除元素,则会截断其他具有相同散列地址的元素的查找地址。因此,要删除一个元素时,可给它做一个删除标记,进行逻辑删除。但这样做的副作用是:执行多次删除后,表面上看起来散列表很满,实际上有许多位置未利用,因此需要定期维护散列表,要把删除标记的元素物理删除。

3.2 拉链法(链接法)

显然,对于不同的关键字可能会通过散列函数映射到同一地址,为了避免非同义词发生冲突,可以把所有的同义词存储在一个线性链表中,这个线性链表由其散列地址唯一标识。假设散列地址为i的同义词链表的头指针存放在散列表的第i个单元中,因而查找、插入和删除操作主要在同义词链中进行。拉链法适用于经常进行插入和删除的情况。

例如,关键字序列为{19,14,23,01,68,20,84,27,55,11,10,79},散列函数H(key)=key % 13,用拉链法处理冲突,建立的表如图所示。

【数据结构(C++版)】哈希表(散列表),数据结构,散列表,哈希算法,数据结构

4. 散列查找及性能分析

散列表的查找过程与构造散列表的过程基本一致。对于一个给定的关键字key,根据散列函数可以计算出其散列地址,执行步骤如下:

初始化:Addr = Hash(key);

  1. 检测查找表中地址为Addr的位置上是否有记录,若无记录,返回查找失败;若有记录,比较它与key的值,若相等,则返回查找成功标志,否则执行步骤2。
  2. 用给定的处理冲突方法计算“下一个散列地址”,并把Addr置为此地址。转入步骤①。

例如,关键字序列{19,14,23,01,68,20,84,27,55,11,10,79}按散列函数H(key) = key % 13和线性探测处理冲突构造所得的散列表L如图所示。

【数据结构(C++版)】哈希表(散列表),数据结构,散列表,哈希算法,数据结构

给定值84的查找过程为:首先求得散列地址H(84)=6,因L[6]不空且L[6]≠84,则找第一次冲突处理后的地址H1=(6+1)%16=7,而L[7]不空且L[7]≠84,则找第二次冲突处理后的地址H2=(6+2)%16=8,L[8]不空且L[8]=84,查找成功,返回记录在表中的序号8。

给定值38的查找过程为:先求散列地址H(38)=12,L[12]不空且L[12]≠ 38,则找下一地址H1=(12+1)%16=13,由于L[13]是空记录,故表中不存在关键字为38的记录。

查找各关键字的比较次数如图所示。

【数据结构(C++版)】哈希表(散列表),数据结构,散列表,哈希算法,数据结构

平均查找长度ASL为

ASL = (1*6 + 2 + 3*3 + 4 + 9) / 12  = 2.5

对同一组关键字,设定相同的散列函数,则不同的处理冲突的方法得到的散列表不同,它们的平均查找长度也不同,本例与上节采用拉链法的平均查找长度不同。

从散列表的查找过程可见:

  1. 虽然散列表在关键字与记录的存储位置之间建立了直接映像,但由于“冲突”的产生,使得散列表的查找过程仍然是一个给定值和关键字进行比较的过程。因此,仍需要以平均查找长度作为衡量散列表的查找效率的度量。
  2. 散列表的查找效率取决于三个因素:散列函数、处理冲突的方法和装填因子。

装填因子。散列表的装填因子一般记为α,定义为一个表的装满程度,即

n—表中记录数,m—散列表长度。

散列表的平均查找长度依赖于散列表的装填因子α,而不直接依赖于n或m。直观地看,α越大,表示装填的记录越“满”,发生冲突的可能性越大,反之发生冲突的可能性越小。

5. 哈希的应用

5.1 位图

5.1.1 位图的概念

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

解决方法:

  1. 遍历:O(N)
  2. 排序:O(NlogN) + 二分查找:O(logN)
  3. 位图

1KB = 1024Byte

1MB = 1024KB

1GB = 1024MB = 1024*1024*1024Byte = 10 7374 1824Byte ≈ 10亿Byte

40亿个整数占用40亿*4 = 160亿Byte,即16GB,将它们全部存储是不可能的,前两种方法不可行。

数据是否存在是两种状态,可以用一个比特位表示这种状态,1表示存在,0表示不存在。

位图就是哈希表直接定址法的变形。用位图表示{ 1,3,7,4,12,16,19,13,22,18 }中的元素是否存在:

上述数组中最大的元素是22,所以我们要表示0~22之间的元素是否存在,理论上只需要开辟23个bit即可,但是内存无法按bit开辟(除了位段),所以我们以Byte为单位开辟空间。

【数据结构(C++版)】哈希表(散列表),数据结构,散列表,哈希算法,数据结构

如何知道数据映射到哪里呢,以19为例:

  1. 先num/8,算出num映射到哪个char里。19/8=2,19在_bits[2]这个char中。
  2. 再num%8,算出num在这个char中的哪一位(从0开始,从后往前数)。19%8=3,19在_bits[2]的第3位。

5.1.2 位图的实现

template<size_t N>
class bitset
{
public:
	//构造函数
	bitset()
	{
		_bits.resize(N / 8 + 1, 0);//N/8只保留整数部分,为防止空间不够,再+1
	}

	//将x映射的bit置1
	void set(size_t x)
	{
		size_t i = x / 8;
		size_t j = x % 8;

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

	//将x映射的bit置0
	void reset(size_t x)
	{
		size_t i = x / 8;
		size_t j = x % 8;

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

	//检测x映射的bit是否为1
	bool test(size_t x)
	{
		size_t i = x / 8;
		size_t j = x % 8;

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

private:
	vector<char> _bits;
};

5.1.3 位图的应用

5.1.3.1

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

解决方法:

  1. 2位位图:00表示没有出现;01表示出现1次;10表示出现2次及以上。1Byte能表示4个数字的出现次数,但是需要修改class bitset的代码。
  2. 2个位图:也是用两个bit表示数字的出现次数,但是是把两个位图拼起来,可以直接复用class bitset的代码。
template<size_t N>
class bitset
{
public:
	//构造函数
	bitset()
	{
		_bits.resize(N / 8 + 1, 0);//N/8只保留整数部分,为防止空间不够,再+1
	}

	//将x映射的bit置1
	void set(size_t x)
	{
		size_t i = x / 8;
		size_t j = x % 8;

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

	//将x映射的bit置0
	void reset(size_t x)
	{
		size_t i = x / 8;
		size_t j = x % 8;

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

	//检测x映射的bit是否为1
	bool test(size_t x)
	{
		size_t i = x / 8;
		size_t j = x % 8;

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

private:
	vector<char> _bits;
};

template<size_t N>
class twobitset
{
public:
	//修改x的出现次数的状态
	void set(size_t x)
	{
		//00 -> 01
		if (_bs1.test(x) == false && _bs2.test(x) == false)
		{
			_bs2.set(x);
		}
		//01 -> 10
		else if (_bs1.test(x) == false && _bs2.test(x) == true)
		{
			_bs1.set(x);
			_bs2.reset(x);
		}
		//10不变
	}

	//打印只出现一次(01)的整数
	void Print()
	{
		for (size_t i = 0; i < N; ++i)
		{
			if (_bs2.test(i))//因为没有11的状态,所以只要第二个bit是1,那就是01的状态
			{
				cout << i << endl;
			}
		}
	}

public:
	bitset<N> _bs1;
	bitset<N> _bs2;
};
5.1.3.2

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

解决方法:

  1. 将一个文件的数字读取到内存的一个位图中,再读取另一个文件,判断其中的数字在不在位图中。这样得到的交集可能会有重复的数字,需要去重;或者,每次找到交集值,都将上面位图对应的值设置为0可以解决找到交集有重复值的问题
  2. 读取文件1的数据映射到位图1,读取文件2的数据映射到位图2。2个位图的对应的位之间进行按位与运算,等于1,则该位对应的数字属于交集。
5.1.3.3

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

解决方法类似5.3.1:00表示没有出现;01表示出现1次;10表示出现2次;11表示出现3次及以上。不超过2次——01 10。

5.2 布隆过滤器

5.2.1 布隆过滤器的提出

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

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

5.2.2 布隆过滤器的概念

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

假设有3个哈希函数。

数据"string"对应的哈希值分别为2、3、7,把这3个位置的bit置1:

【数据结构(C++版)】哈希表(散列表),数据结构,散列表,哈希算法,数据结构

数据"vector"对应的哈希值分别为1、3、5,把这3个位置的bit置1:

【数据结构(C++版)】哈希表(散列表),数据结构,散列表,哈希算法,数据结构

查找数据"list"是否存在:数据"list"对应的哈希值分别为1、4、5,而4这个bit位为0,说明没有任何一个值映射到这个bit位上,因此"list"一定不存在。

查找数据"deque"是否存在:数据"deque"对应的哈希值分别为2、3、5,这3个bit位都为1,但是只能说明"deque"可能存在。因为这3个bit位可能都被其他数据置1了,即使"deque"不存在,"deque"对应的哈希值的bit位也可能全为1。

布隆过滤器不能直接支持删除工作,因为在删除一个元素时,可能会影响其他元素。比如:删除上图中"vector",如果直接将该元素所对应的bit位置0,"string"也被删除了,因为这两个元素在多个哈希函数计算出的bit位上刚好有重叠。

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

缺陷:

  1. 无法确认元素是否真正在布隆过滤器中
  2. 存在计数回绕

【数据结构(C++版)】哈希表(散列表),数据结构,散列表,哈希算法,数据结构

来源:详解布隆过滤器的原理,使用场景和注意事项 - 知乎

5.2.3 布隆过滤器的实现

template<size_t N>
class bitset
{
public:
	//构造函数
	bitset()
	{
		_bits.resize(N / 8 + 1, 0);//N/8只保留整数部分,为防止空间不够,再+1
	}

	//将x映射的bit置1
	void set(size_t x)
	{
		size_t i = x / 8;
		size_t j = x % 8;

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

	//将x映射的bit置0
	void reset(size_t x)
	{
		size_t i = x / 8;
		size_t j = x % 8;

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

	//检测x映射的bit是否为1
	bool test(size_t x)
	{
		size_t i = x / 8;
		size_t j = x % 8;

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

private:
	vector<char> _bits;
};

struct BKDRHash
{
	size_t operator()(const string& s)
	{
		size_t hash = 0;
		for (auto ch : s)
		{
			hash += ch;
			hash *= 31;
		}
		return hash;
	}
};

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

struct DJBHash
{
	size_t operator()(const string& s)
	{
		size_t hash = 5381;
		for (auto ch : s)
		{
			hash += (hash << 5) + ch;
		}
		return hash;
	}
};

//N:最多会插入key数据的个数
template<size_t N,
		 class K = string,
		 class Hash1 = BKDRHash,
		 class Hash2 = APHash,
		 class Hash3 = DJBHash>
class BloomFilter
{
public:
	void set(const K& key)
	{
		size_t len = N * _X;
		size_t hash1 = Hash1()(key) % len;
		_bs.set(hash1);

		size_t hash2 = Hash2()(key) % len;
		_bs.set(hash2);

		size_t hash3 = Hash3()(key) % len;
		_bs.set(hash3);

		//cout << hash1 << " " << hash2 << " " << hash3 << " " << endl << endl;
	}

	bool test(const K& key)
	{
		size_t len = N * _X;

		size_t hash1 = Hash1()(key) % len;
		if (!_bs.test(hash1))
		{
			return false;
		}

		size_t hash2 = Hash2()(key) % len;
		if (!_bs.test(hash2))
		{
			return false;
		}

		size_t hash3 = Hash3()(key) % len;
		if (!_bs.test(hash3))
		{
			return false;
		}

		// 在      不准确的,存在误判
		// 不在    准确的

		return true;
	}
private:
	static const size_t _X = 4;
	bitset<N * _X> _bs;
};

5.2.4 布隆过滤器的应用

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

假设平均每个query是50Byte, 100亿个query是5000亿Byte,即500GB。

近似算法:布隆过滤器(有误判)

精确算法:哈希切分

【数据结构(C++版)】哈希表(散列表),数据结构,散列表,哈希算法,数据结构文章来源地址https://www.toymoban.com/news/detail-615797.html

到了这里,关于【数据结构(C++版)】哈希表(散列表)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java学数据结构(4)——散列表Hash table & 散列函数 & 哈希冲突

    1.散列表,key,散列函数; 2.哈希冲突的解决; 3.string中的hashCode; 查找树ADT,它允许对元素的集合进行各种操作。本章讨论散列表(hash table)ADT,不过它只支持二叉查找树所允许的一部分操作。散列表的实现常常叫作散列(hashing)。散列是一种用于以常数平均时间执行插入、删除和

    2024年02月10日
    浏览(46)
  • 一篇就能学懂的散列表,让哈希表数据结构大放光彩

    目录 1.散列表的基本概念 2.散列表的查找 3.散列函数的构造方法 1.直接定址法 2.除留余数法 4.散列表解决冲突的方法 1.开放定址法 2.链地址法 基本思想 :记录的存储位置与之间存在的对应关系 对应关系——hash函数 Loc(i) = H(keyi) Hash:哈希——翻译为:散列、杂凑(感

    2024年02月09日
    浏览(46)
  • C++:【数据结构】哈希表

    哈希表(hash table)又叫散列表,是一种很实用的数据结构。首先来看一下百度给出的定义:散列表,是 根据关键码值(Key value)而直接进行访问的数据结构 。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放

    2024年02月03日
    浏览(41)
  • 【数据结构篇C++实现】- 哈希表

    友情链接:C/C++系列系统学习目录 哈希表:也叫做散列表。是根据和值(Key-Value)直接进行访问的数据结构。也就是说,它通过 key 和一个映射函数 Hash(key) 计算出对应的一个存储位置,然后把键值对映射到哈希表上的对应位置来访问记录,以加快查找的速度。这

    2024年02月02日
    浏览(35)
  • 【数据结构与算法】前缀和+哈希表算法

    关于前缀和和哈希这两个概念大家都不陌生,在之前的文章中也有过介绍:前缀和与差分算法详解 而哈希表最经典的一题莫过于 两数之和 题目链接 题目描述: 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它

    2024年02月01日
    浏览(102)
  • 数据结构,查找算法(二分,分块,哈希)

    一、查找算法         1、二分查找:(前提条件: 必须有序的序列) 2、分块查找:(块间有序,块内无序)     索引表  +  源数据表     思路:     (1)先在索引表中确定在哪一块中     (2)再遍历这一块进行查找 //索引表 typedef  struct  {     int max; //块中最大值

    2024年02月11日
    浏览(46)
  • 【数据结构】哈希表(算法比赛向)

    目录 一:介绍 一:什么是哈希表 二、哈希表的应用 二:存储结构 a.拉链法: b.开放寻址法: 三:扩展 a.字符串哈希: 例题:      一:什么是哈希表 1、哈希表也叫散列表,哈希表是一种数据结构,它提供了快速的插入操作和查找操作,无论哈希表总中有多少条数据,插

    2023年04月25日
    浏览(39)
  • 【数据结构与算法】哈希—— 位图 | 布隆过滤器 | 哈希切割

    🐱作者:一只大喵咪1201 🐱专栏:《数据结构与算法》 🔥格言: 你只管努力,剩下的交给时间! 哈希是一种映射思想,这里再讲解两种应用哈希思想的数据结构。 问题: 给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数

    2024年02月02日
    浏览(44)
  • 【数据结构与算法——TypeScript】哈希表

    哈希表介绍和特性 哈希表是一种非常重要的数据结构,但是很多学习编程的人一直搞不懂哈希表到底是如何实现的。 在这一章节中,我门就一点点来实现一个自己的哈希表。 通过实现来理解哈希表背后的原理和它的优势。 几乎所有的编程语言都有直接或者间接的应用这种数

    2024年02月13日
    浏览(32)
  • 算法数据结构基础——哈希表(Hash Table)

    哈希表(Hash Table) :也叫做散列表。是根据关键码值(Key Value)直接进行访问的数据结构。 哈希表通过「键 key 」和「映射函数 Hash(key) 」计算出对应的「值 value 」,把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做「哈希函数(散列函数

    2024年02月13日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包