精华内容
下载资源
问答
  • 线性探测
    2022-06-11 23:41:26

    答案:是

    更多相关内容
  • 内图使用开放寻址和线性探测的整数 HashMap
  • 从键盘输入各记录,以用户名为关键字建立哈希表, 哈希函数用除留取余数法构造, 采用线性探测法解决冲突。可以插入、查找、删除并显示给定用户名的记录, 并计算查找长度, 哈希表保存到文件中。 测试数据: 取自己...
  • c代码实现哈希表线性探测再散列。关键字均为纯数字。查找时为单次查找,未加入循环
  • 1)设计几个不同的哈希函数,比较他们的地址冲突率(可以用更大的名字集合做实验)。 (2)研究这30个人名的特点,努力找一个哈希函数,使得对于不同的拼音名一定不发生地址冲突。 (3)在哈希函数确定的前提下尝试...
  • NULL 博文链接:https://128kj.iteye.com/blog/1744810
  • 1、哈希表-线性探测法理论 线性探测法的理论我们在上一篇博客已经阐述了。 现在我们来看看线性探测法的增删查的代码思想: 1.1、哈希表的增加元素 注意: 往后遍历寻找空闲位置的时候,要注意是环形遍历哦!不然...

    1、哈希表-线性探测法理论

    在这里插入图片描述
    线性探测法的理论我们在上一篇博客已经阐述了。

    现在我们来看看线性探测法的增删查的代码思想:

    1.1、哈希表的增加元素

    在这里插入图片描述
    注意:

    • 往后遍历寻找空闲位置的时候,要注意是环形遍历哦!不然访问数组就越界了。
    • 在添加元素,发生位置被占用,即发生哈希冲突后,在向后遍历寻找空闲位置的时候,我们要知道,这个空闲的位置是有两种情况的:
      • 1、这个位置一直是空的,没放过元素
      • 2、这个位置是空的,以前放过元素,后来被删除了

    1.2、哈希表的查询操作

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

    • 当用哈希函数计算得出的下标值是3,然后去访问数组,查询时,发现该值不等于要查询的元素的值val,说明当时放val的时候发生了哈希冲突,这时候就要向后遍历了;
    • 访问4下标的时候发现这个位置是空的(空的有两种情况),如果这个位置一直是空的,则就不用继续向后找了,val不存在!因为是线性探测法,所以当时val如果要放的时候肯定是要放在这里的。
    • 但是如果这个位置是空的,但是之前放过元素,后来被删除了,这个位置之前存放了元素,然后val插入的时候,就插到后面的空闲的位置了,所以此时我们还要继续往后遍历寻找val值。

    在这里插入图片描述
    所以我们需要定义一个Bucket节点来表示每一个元素的所有的内容。
    在这里插入图片描述

    //桶的状态
    enum State
    {
    	STATE_UNUSE, //从未使用过的桶
    	STATE_USING, //正在使用的桶 放着是一个有效的元素,没有被删过 
    	STATE_DEL,  //元素被删除了的桶,认为桶里的元素无效了 
    };
    //我们删除桶里的元素,并不是真正把值删除掉,而是把桶的状态置为STATE_DEL就认为桶里的元素无效了 
    //桶的类型
    struct Bucket
    {
    	Bucket(int key = 0, State state = STATE_UNUSE)
    		: key_(key)
    		, state_(state)
    	{}
    
    	int key_;      //存储的数据
    	State state_;  //桶的当前状态
    };
    
    

    1.3、哈希表的删除操作

    在这里插入图片描述

    2、哈希表-线性探测法代码实现

    2.1、素数表中的素数

    求素数的代码:(用于素数表中的素数取值)
    在这里插入图片描述

    在这里插入图片描述

    int main()
    {
    	int data = 3;
    
    	for (int i = data; i < 10000; i++)
    	{
    		int j = 2;
    		for (; j < i; j++)
    		{
    			if (i % j == 0)
    				break;
    		}
    
    		if (j == i)
    			cout << i << " ";
    	}
    	cout << endl;
    
    	return 0;
    }
    
    

    代码:

    #include <iostream>
    using namespace std;
    
    //桶的状态
    enum State
    {
    	STATE_UNUSE, //从未使用过的桶
    	STATE_USING, //正在使用的桶 放着是一个有效的元素,没有被删过 
    	STATE_DEL,  //元素被删除了的桶,认为桶里的元素无效了 
    };
    //我们删除桶里的元素,并不是真正把值删除掉,而是把桶的状态置为STATE_DEL就认为桶里的元素无效了
    //不用将其置为0或-1...
    
    //桶的类型
    struct Bucket
    {
    	Bucket(int key = 0, State state = STATE_UNUSE)	//刚开始都是STATE_UNUSE,没有使用过的状态
    		: key_(key)
    		, state_(state)
    	{}
    
    	int key_;      //存储的数据
    	State state_;  //桶的当前状态
    };
    
    //线性探测哈希表类型  
    class HashTable
    {
    public:
    	//构造
    	HashTable(int size = primes_[0], double loadFactor = 0.75)//构造函数 
    		: useBucketNum_(0)
    		, loadFactor_(loadFactor)
    		, primeIdx_(0)
    	{
    		//把用户传入的size调整到最近的比较大的素数上
    		if (size != primes_[0])
    		{
    			for (; primeIdx_ < PRIME_SIZE; primeIdx_++)
    			{
    				if (primes_[primeIdx_] >= size)
    					break;
    			}
    			//用户传入的size值过大,已经超过最后一个素数,调整到最后一个素数
    			if (primeIdx_ == PRIME_SIZE)
    			{
    				primeIdx_--;
    			}
    		}
    
    		tableSize_ = primes_[primeIdx_];
    		table_ = new Bucket[tableSize_];//开辟构造,调用Bucket的默认构造函数初始化 
    	}
    	
    	//析构
    	~HashTable()//析构函数 
    	{
    		delete[]table_;
    		table_ = nullptr;
    	}
    
    public:
    	//插入元素,这里不去重,k值可以重复插入
    	bool insert(int key)
    	{
    		//考虑扩容
    		double factor = useBucketNum_ * 1.0 / tableSize_;
    		cout << "factor:" << factor << endl;
    		if (factor > loadFactor_)
    		{
    			//哈希表开始扩容
    			expand();
    		}
    
    		int idx = key % tableSize_;//计算下标 
    
    		int i = idx;
    		do
    		{
    			if (table_[i].state_ != STATE_USING)
    			{
    				table_[i].state_ = STATE_USING;
    				table_[i].key_ = key;
    				useBucketNum_++;
    				return true;//O(1)
    			}
    			i = (i + 1) % tableSize_;//环形路径 
    		} while (i != idx);//O(n) 
    		//最多跑一圈,而且不可能跑一圈,因为哈希表是不可能放满的,超过加载因子就扩容 
    		//do while 是先执行一次,再判断循环 
    		return false;
    	}
    
    	//删除元素,只是把当前状态修改一下而已 
    	bool erase(int key)
    	{
    		int idx = key % tableSize_;//计算出哈希值 
    
    		int i = idx;
    		do
    		{
    			if (table_[i].state_ == STATE_USING && table_[i].key_ == key)
    			{
    				table_[i].state_ = STATE_DEL;
    				useBucketNum_--;
    			}
    			i = (i + 1) % tableSize_;
    		} while (table_[i].state_ != STATE_UNUSE && i != idx);	//table_[i].state_ != STATE_UNUSE表示后面确实没有这个元素
    
    		return true;
    	}
    
    	//查询  count(key)
    	bool find(int key)
    	{
    		int idx = key % tableSize_;
    
    		int i = idx;
    		do
    		{
    			if (table_[i].state_ == STATE_USING && table_[i].key_ == key)
    			{
    				return true;
    			}
    			i = (i + 1) % tableSize_;
    		} while (table_[i].state_ != STATE_UNUSE && i != idx);
    
    		return false;
    	}
    
    private:
    	//扩容操作
    	void expand()
    	{
    		++primeIdx_;	//取素数表后一个元素值
    		if (primeIdx_ == PRIME_SIZE)//越界了 
    		{
    			throw "HashTable is too large, can not expand anymore!";
    		}
    
    		Bucket* newTable = new Bucket[primes_[primeIdx_]];
    		for (int i = 0; i < tableSize_; i++)
    		{
    			if (table_[i].state_ == STATE_USING)//旧表有效的数据,重新哈希放到扩容后的新表
    			{
    				int idx = table_[i].key_ % primes_[primeIdx_];
    
    				int k = idx;
    				do
    				{
    					if (newTable[k].state_ != STATE_USING)//空闲的 
    					{
    						newTable[k].state_ = STATE_USING;
    						newTable[k].key_ = table_[i].key_;
    						break;
    					}
    					k = (k + 1) % primes_[primeIdx_];
    				} while (k != idx);
    			}
    		}
    
    		delete[]table_;
    		table_ = newTable;
    		tableSize_ = primes_[primeIdx_];
    	}
    
    private:
    	Bucket* table_;//指向动态开辟的哈希表,不要使用vector,因为它是二倍自动扩容,自增长
    	//要用vector也可以,因为哈希表有装载因子,达到0.75,哈希表进行扩容 
    	int tableSize_;//哈希表当前的长度
    	int useBucketNum_;//已经使用的桶的个数
    	double loadFactor_;//哈希表的装载因子
    
    	static const int PRIME_SIZE = 10;//素数表的大小
    	static int primes_[PRIME_SIZE];//素数表
    	int primeIdx_;//当前使用的素数在素数表中的下标值 
    };
    
    int HashTable::primes_[PRIME_SIZE] = { 3, 7, 23, 47, 97, 251, 443, 911, 1471, 42773 };//素数表的定义 
    //素数表的最后几个元素代表开辟哈希表数组堆空间的最大的一些内存大小,再大的话堆内存就开辟失败了 
    //所有哈希表的素数表都是一样的,可以定义成静态的
    
    int main()
    {
    	HashTable htable;
    	htable.insert(21);
    	htable.insert(32);
    	htable.insert(14);
    	htable.insert(15);
    
    	htable.insert(22);
    
    	cout << htable.find(14) << endl;
    	htable.erase(14);
    	cout << htable.find(14) << endl;
    
    	return 0;
    }
    
    展开全文
  • Go 中的线性探测哈希表 这是用于线性探测哈希表的模板。 因为这是一个探测哈希表,所以只能插入或修改条目(即不能删除)。 并且必须有一个无效的密钥__KEY_NIL用于标记未使用的桶。 优点(相对于 Go 自己的地图类型...
  • 线性探测-闭散列

    2021-05-27 11:40:31
    线性探测的实现目录:一.线性探测的概念二.线性探测原理三.功能性接口1.构造2.insert3.Capacity4.Swap5.find6.erase 目录: 一.线性探测的概念 我们在这里讲到的线性探测是解决哈希冲突中闭散列的一种方式 闭...

    在这里插入图片描述

    目录:

    一.线性探测的概念

    我们在这里讲到的线性探测是解决哈希冲突中闭散列的一种方式

    闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把key存放到冲突位置中的“下一个” 空位置中去。
    ~
    线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。

    二.线性探测原理

    在这里插入图片描述

    闭散列解决哈希冲突的方法就是将元素后移,存放到为空的位置去.

    三.功能性接口

    1.构造

    enum STATE{		//创建一个枚举
    
    	EXIST,		//存在状态
    	DELETE,		//假删除状态
    	EMPTY		//空状态
    };
    
    template<class K, class V>
    struct HashNode{	//创建哈希结构体保存对应的KV键值对,并且将这个表的初始状态变为空
    
    	pair<K, V> _kv;
    	STATE _state = EMPTY;
    };
    
    //顺序表实现hash
    template<class K, class V>
    class HashTable{		//hash创建
    
    public:
    	typedef HashNode<K, V> Node;		//定义别名
    
    	HashTable(size_t n = 10)		//构造函数构造缺省值为10
    		:_hTable(n)
    		, _size(0)		//存在元素改为0
    	{}
    

    2.insert

    步骤:
    1.计算插入元素的哈希位置
    2.判断对应的位置是否有元素存在
    3.有元素则向后遍历找空存放
    4.无元素则直接存放

    	bool insert(const pair<K, V>& kv){
    
    		//0.判断容量是否够用
    		checkCapacity();	//调用函数
    		//1.计算哈希位置
    		int idx = kv.first%_hTable.size();
    
    		//2.判断key是否存在
    		while (_hTable[idx]._state != EMPTY){
    
    			//如果当前位置数据有效,且key相同
    			if (_hTable[idx]._state == EXIST
    				&&kv.first == _hTable[idx]._kv.first)
    			{
    				return false;
    			}
    			//继续搜索
    			++idx;
    			if (idx == _hTable.size())
    				idx = 0;
    		}
    		//插入
    		_hTable[idx]._kv = kv;
    		_hTable[idx]._state = EXIST;
    		++_size;
    
    		return true;
    	}
    

    3.Capacity

    在这里插入图片描述

    	void checkCapacity(){
    	
    		//负载因子: < 1
    		//存在的元素/容量  0.7
    		if (_hTable.size() == 0 || _size * 10 / _hTable.size() >= 7){//当内部的元素存储超过7成的时候就开辟新的表
    
    			//开新表
    			int newC = _hTable.size() == 0 ? 10 : 2 * _hTable.size();	//创建出对应的二倍的空间
    			HashTable<K, V> newHt(newC);
    
    			for (int i = 0; i < _hTable.size(); ++i){		//在for循环内部
    
    				//插入状态为exist的数据
    				if (_hTable[i]._state == EXIST)	//将内部存在的元素
    				{
    					newHt.insert(_hTable[i]._kv);	//依次在新表里面进行插入
    				}
    			}
    			Swap(newHt);	//交换新表和旧表
    		}
    	}
    

    4.Swap

    	void Swap(HashTable<K, V>& Ht){	//这里的交换就是让新的表指向对应的位置,容量进行交换
    
    		swap(_hTable, Ht._hTable);
    		swap(_size, Ht._size);
    
    	}
    

    5.find

    步骤:
    1.按照查找位置计算所在的位置
    2.如果对应的kv键值对是完全对应的,则直接输出
    3.如果没有找到,则继续向后进行遍历

    	Node* find(const K& key){
    
    		//计算对应的位置
    		int idx = key%_hTable.size();	//先找出所在元素在哈希表中的位置
    		while (_hTable[idx]._state != EMPTY){		//判断对应的位置是否有元素的存在
    
    			if (_hTable[idx]._state == EXIST
    				&& key == _hTable[idx]._kv.first)	//如果元素存在且对应的键值相互对应
    			{
    				return &_hTable[idx];	//则找到,直接输出
    			}
    			++idx;	//没找到则向后遍历
    			if (idx == _hTable.size())	
    			//如果遍历到最后一个位置没有找到,则变为0从第一个重新开始查找
    			{
    				idx = 0;
    			}
    		}
    		return nullptr;	//实在没有找到则直接返回空
    	}
    

    6.erase

    步骤:
    1.找到对应的元素进行删除
    2.注意这里的删除是假删除,元素还存在,只不过将其置为DELETE状态
    3.这里的假删除是为了在插入的时候可以正常的插入.

    	bool erase(const K& key){
    
    		Node* node = find(key);
    		if (node){
    
    			//假删除
    			--_size;
    			node->_state = DELETE;
    			return true;
    		}
    		return false;
    	}
    
    
    private:
    	vector<Node> _hTable;
    	size_t _size;	//有效元素的个数
    };
    

    这就是对于线性探测的实现,主要对于它产生哈希冲突的时候是如何解决的理解.

    展开全文
  • #include#define HashLength 23using namespace std;//哈希函数int HashFuc...}//线性探测再散列int *HashReLineExplor(int A[], int k,int h[],int m)//关键字数组、关键字个数、哈希表、哈希表长度{for (int i = 0...

    #include

    #define HashLength 23

    using namespace std;

    //哈希函数

    int HashFuc(int i,int length)

    {

    return i%length;

    }

    //线性探测再散列

    int *HashReLineExplor(int A[], int k,int h[],int m)//关键字数组、关键字个数、哈希表、哈希表长度

    {

    for (int i = 0; i < m; i++)

    h[i] = NULL;

    for (int j = 0; j < k; j++)

    {

    int loc = HashFuc(A[j], HashLength);

    while (h[loc])

    {

    loc=loc++%m;//寻找第一个空位置

    }

    h[loc] = A[j];

    }

    return h;

    }

    int main()

    {

    int Hash[25];//哈希表

    int Key[20] = { 23, 26, 14, 22, 24, 38, 32, 120, 29, 93, 83, 21, 11, 23, 43, 123, 94, 93, 92, 91 };//关键字

    HashReLineExplor(Key, 20, Hash, 25);

    for (int i = 0; i < 25; i++)

    {

    if (Hash[i])

    {

    printf("第%2d个元素是:%4d\n", i, Hash[i]);

    }

    }

    return 0;

    }

    数组中元素:23, 26, 14, 22, 24, 38, 32, 120, 29, 93, 83, 21, 11, 23, 43, 123, 94, 93, 92, 91

    哈希表中元素:

    第 0个元素是:  23 第 1个元素是:  24 第 2个元素是:  93 第 3个元素是:  26 第 4个元素是:  23 第 5个元素是: 120 第 6个元素是:  29 第 7个元素是:  94 第 8个元素是: 123 第 9个元素是:  32 第10个元素是:  93 第11个元素是:  11 第12个元素是:  92 第14个元素是:  14 第15个元素是:  38 第16个元素是:  83 第20个元素是:  43 第21个元素是:  21 第22个元素是:  22 第23个元素是:  91 请按任意键继续. . .

    展开全文
  • 线性探测再散列详解

    2021-11-11 20:29:01
    线性探测再散列是这样的,以408 10年真题为例,当遇到18时第一次散列值为5,冲突。 由开放定址法公式,Hi={H(key)+di}mod m 误导之处就是 ⚠️注意此处的M是表长而不是散列函数的值 很多人把再散列当作再用给定的H...
  • 1、简介 线程内共享,线程间隔离。 线程本地变量 与lock相比: ThreadLocal:空间换时间 ...key定位采用hash,碰撞后采用线性探测法,未再使用链表。 private static int nextIndex(int i, int len) { retu
  • 线性探测再散列

    万次阅读 多人点赞 2019-10-07 09:57:11
    处理冲突的方法: 开放寻址法:Hi=(H(key) + di) MOD m, i=1,2,…, k(k),其中H(key)为散列函数,m为散列表长,di为增量序列,可有下列三种取法: 1.di=1,2,3,…, m-1,称线性探测再散列; 2.di=1^2, -1^2, 2^2,-2^...
  • 哈希表:线性探测法和链地址法求查找成功与不成功的平均查找
  • 线性探测法理论: 哈希表增加元素 增加元素注意两点: 往后遍历寻找空闲位置是环形遍历,否则访问会数组越界 发生哈希冲突找空闲位置的时候,有两种情况:这个位置一直是空的没放过元素;这个位置是空的,以前放过...
  • 线性探测法 将关键字序列(7、8、30、11、18、9、14)散列存储到散列表中 (7) Key 7 8 30 11 18 9 14 H(Key) 0 3 6 5 5 5 6 冲突处理:(位置被占有继续往下找) 地址 0 1 2 3 4 5 6 7 8 9 关键字...
  • 哈希表(线性存储)+ 线性探测法解决哈希冲突: 将关键路径通过哈希函数映射到哈希表中,哈希表是线性的结构体数组,其中,线性存储中,哈希长度这里要提前给出,给出的长度一般是是大于插入数据数组的长度的最小...
  • 散列表查找——线性探测

    千次阅读 2021-12-13 21:43:11
    //散列表查找——线性探测法 #include<iostream> #include<stdlib.h> using namespace std; void print(int list[],int e,int key,int a){ int n=e%key;//对输入的输求余 while(list[n]!=-1){ n...
  • 开放寻址——线性探测

    千次阅读 2018-12-06 11:43:37
    开放寻址——线性探测 分离链接散列算法还有一个亟待解决的缺点:需要指针,由于给新单元分配地址需要时间,这就导致了速度减慢,所以不太好。还有,因为链表是次第关联的结构,实现算法的代码自身的复杂程度和出错...
  • 先上结论:线性探测再散列就是王道P282(不同版本页码不一致)中的线性探测法。 对于2019年真题中线性探测再散列,严的紫书在P257中明确写到了线性探测再散列的解释。即如下图: 而王道P282中线性探测法如下图:...
  • 线性探测法的查找函数题目答案思路 题目 答案 Position Find( HashTable H, ElementType Key ) { int i,flag=0; i=Hash(Key,H->TableSize); while(H->Cells[i].Info!=Empty&&H->Cells[i]....
  • 下面主要介绍线性探测法:也是一种比较常用的处理冲突的方法(但是极易产生堆积问题) 线性探测法 即从发生冲突的地址(记做d)开始,依次探查d的下一个地址,直至找到一个空位置为止。记住这句话。查找时若查到空...
  • 线性探测解决hash冲突

    2020-05-30 15:25:38
    我们来简单的例子说明什么是线性探测 假设我们有一个数组 假设我们用当前公式计算当前数据在数组中的下标位置 int i = num%11; 假设我们有一组数据{1,2,3,11,12,13,14}需要放置在数组中 那么他们对应的下标位置应该...
  • ThreadLocalMap线性探测法解决hash冲突

    千次阅读 2020-08-01 17:20:33
    第四、ThreadLocalMap中的set() ThreadLocalMap使用闭散列:(开放地址法或者也叫线性探测法)解决哈希冲突,线性探测法的地址增量di = 1, 2, … 其中,i为探测次数。该方法一次探测下一个地址,直到有空的地址后插入...
  • 用纯C99编写的线性探测无序哈希表的实现,没有外部依赖项 线性哈希是根据MIT许可获得许可的,有关更多详细信息,请参见LICENSE。 散列功能 linear_hash使用djb2的实现,下面是参考实现,也可以在上 unsigned long ...
  •  开放地址法也分为线性探测、平方探测和双散列,这里我先说最简单的线性探测- -、。线性探测就是在发生冲突后,在原来的地址上往下一个地址找,一个一个的往下探测,直到找到空位置为止。  思路大概就是上面...
  • 哈希表之线性探测和二次探测

    千次阅读 2020-02-29 17:58:35
    1.di=1,2,3,…, m-1,称线性探测再散列; 2.di=1^2, -1^2, 2^2,-2^2, 3^2, …, ±(k)^2,(k)称二次探测再散列; 3.di=伪随机数序列,称伪随机探测再散列。 再散列法:Hi=RHi(key), i=1,2,…,k. RHi均是不同...
  • 遇到碰撞问题:线性探测法; 线性探测法:哈希表存储了数据就重新寻找数据索引存储数据; 线形探测公式:哈希表索引= ( 哈希表索引 + 1) % 哈希表长度; 除留取余法:通过将数据和哈希表长度比较获取索引位置; ...
  • 再散列和平方散列不同,再散列是遇到冲突时前进一位。 计算查找失败的平均查找长度,要特别注意防止思维定式,在查找失败的情况下,既不是根据表中的元素个数,也不是根据表长来计算平均查找长度。...
  • 拉链法和线性探测

    2019-07-24 20:47:00
    在使用率 1/8~1/2情况下,线性探测使用4N~16N个引用。 方法 N个元素所需的内存 拉链法 48N + 32M 线性探测法 32N ~ 128N 二叉查找树 56N 转载于:https://www.cnblogs.com/0ffff/p/11240684.html

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 35,454
精华内容 14,181
关键字:

线性探测