哈希


一、直接定制法
1、统计每个字符出现的次数
以每一个字符的asc码作为下标,统计每个字符出现的次数,遇到的第一个1即第一个出现一次的字符:时间复杂度为O(n);空间复杂度为O(1),因为该字符串为一个常量,所以空间复杂度为O(1)
2、按升序排序:把字符串收集回来(因为下标是有次序的)
二、除留余数法
三、平方取中法
四、折叠法(分段后相加,取相加后结果的后几位)
五、随机数法(给定一个数,让随机函数随机一个地址)

六、数学分析法

程序实现:
闭散列:从发生哈希冲突的位置开始,找下一个空余位置
给每一个位置给定一个状态:EMPTY:空状态;EXIST:存在状态,空间中有数据;delete:删除状态
 1、线性探测:逐个朝后找下一个位置
插入:计算出该数字的哈希地址,若该地址处没有元素为空状态,则插入;若是有,则插入下一个状为空的元素
删除:计算出该数字的哈希地址,若该为置为存在状态则,判断该元素是否为要删除的元素,删除后将该位置置为删除状态
查找:计算出该数字的哈希地址,判断是否为要查找的数字,若是,返回下标;若不是,往后继续查找,判断是否为要查找的数字(遇到空则继续探测,遇到存在
状态则进行比较,查完都没找到,则不存在这个元素)
缺点:存在数据的堆积:只要一个冲突会引起后面的都发生冲突如:3 13 14 15 16,13会占据14的位置,14会占据15的位置……

.h

 
# pragma once
# include <stdio.h>
# include<stdlib.h>
# include<string.h>
# include<assert.h>
#define MAX_SIZE 10
typedef int DataType;
typedef enum{
 EXIST,EMPTY,DELETE
}State;
typedef struct HTElem
{
 DataType _data;
 State _state;
}HTElem;
typedef struct HashTable
{
 HTElem _array[MAX_SIZE];
 int _total;//哈希表中元素的个数(包括存在和删除)
 int _size;//计算哈希表中有效元素的个数
 }HashTable,HT;
void HashTableInit(HT *ht);
 void HashTableInsert(HT *ht, DataType data);
void HashTableDelete(HT *ht, DataType data);
int HashTableFind(HT *ht, DataType data);
int HashTableSize(HT *ht);
int HashTableEmpty(HT *ht);


.c
 
# include"hsxihanshu.h"
void HashTableInit(HT *ht)
{
 int i = 0;
 for (; i < MAX_SIZE; ++i)
  ht->_array[i]._state = EMPTY;
 ht->_size = 0;
 ht->_total = 0;
}
void HashTableInsert(HT *ht, DataType data)
{
 int hashAddr = -1;
 int i = 0;
 assert(ht);
 if (ht->_total == MAX_SIZE)
  return;
 //计算哈希地址
 hashAddr = hashFunc(data);
 while (EMPTY != ht->_array[hashAddr]._state)
 {
  if (EXIST == ht->_array[hashAddr]._state)
  {
   if (data == ht->_array[hashAddr]._data)
    return;
  }
  hashAddr++;
  if (hashAddr == MAX_SIZE)
   hashAddr = 0;
 }
 //插入元素
 ht->_array[hashAddr]._data = data;
 ht->_array[hashAddr]._state = EXIST;
 ht->_size++;
 ht->_total++;
}
int hashFunc(DataType data)
{
 return data%MAX_SIZE;
}
void HashTableDelete(HT *ht, DataType data)
{
 int ret = -1;
 assert(ht);
 ret = HashTableFind(ht, data);
 if (-1 != ret)
 {
  ht->_array[ret]._state = DELETE;
  ht->_size--;
 }
}
int HashTableFind(HT *ht, DataType data)
{
 int hashAddr = -1;
 int startAddr = -1;
 assert(ht);
 hashAddr = hashFunc(data);
 startAddr = hashAddr;
 while (ht->_array[hashAddr]._state != NULL)
 {
  if (EXIST == ht->_array[hashAddr]._state)
  {
   if (data == ht->_array[hashAddr]._data)
    return hashAddr;
  }
  hashAddr++;
  if (hashAddr == MAX_SIZE)//越界了,从头再找
   hashAddr = 0;
  if (hashAddr == startAddr)
   return -1;
 }
 return -1;//没有找到
}
int HashTableSize(HT *ht)
{
 return ht->_size;
}
int HashTableEmpty(HT *ht)
{
 assert(ht);
 return 0 == ht->_size;
}


test.c
 
# include"hsxihanshu.h"
void test()
{
 HashTable ht;
 HashTableInit(&ht);
 HashTableInsert(&ht, 23);
 HashTableInsert(&ht, 14);
 HashTableInsert(&ht, 74);
 HashTableInsert(&ht, 33);
 HashTableInsert(&ht, 19);
 HashTableInsert(&ht, 29);
 printf("size=%d\n", HashTableSize(&ht));
 if (-1 != HashTableFind(&ht, 33))
 printf("该元素不存在");
 else
  printf("该元素存在");
 if (3 != HashTableFind(&ht, 33))
 printf("该元素不存在");
 else
  printf("该元素存在");
 }
void test2()
{
 HashTable ht;
 HashTableInit(&ht);
 HashTableInsert(&ht, 23);
 HashTableInsert(&ht, 14);
 HashTableInsert(&ht, 74);
 HashTableInsert(&ht, 33);
 HashTableInsert(&ht, 19);
 HashTableInsert(&ht, 29);
 HashTableDelete(&ht, 33);
 if (-1 != HashTableFind(&ht, 33))
  printf("该元素不存在");
 else
  printf("该元素存在");
 if (3 != HashTableFind(&ht, 33))
  printf("该元素不存在");
 else
  printf("该元素存在");
 printf("size=%d\n", HashTableSize(&ht));
}
int main()
{
 //test();
 test1();
 system("pause");
 return 0;
}


结果:
2.二次探测:
解决数据堆积的方法:二次探测:是数据更加离散:H0表示第一次探测的地址
第i次探测:Hi=H0+i^2;第Hi+1次探测:Hi+1=H0+(i+1)^2
Hi+1=Hi+2*i+1
二次探测的缺陷:可能会越界,因为每次都在累加,距离不断加大
解决二次探测的缺陷的方法:越界后模回去

.h
# pragma once
# include <stdio.h>
# include<stdlib.h>
# include<string.h>
# include<assert.h>
#define MAX_SIZE 10
typedef int DataType;
typedef enum{
	EXIST, EMPTY, DELETE
}State;
typedef struct HTElem
{
	DataType _data;
	State _state;
}HTElem;
typedef struct HashTable
{
	HTElem _array[MAX_SIZE];
	int _total;//哈希表中元素的个数(包括存在和删除),防止出现死循环
	int _size;//计算哈希表中有效元素的个数
	int _IsLineDetective;//是否为线性探测
}HashTable, HT;
//初始化
void HashTableInit(HT *ht,int IsLineDetetive);
//插入
void HashTableInsert(HT *ht, DataType data);
//删除
void HashTableDelete(HT *ht, DataType data);
//查找
int HashTableFind(HT *ht, DataType data);
//计算哈希表格中的元素个数
int HashTableSize(HT *ht);
//判断哈希表格是不是空的
int HashTableEmpty(HT *ht);

.c

# include"haxihanshu.h"
//初始化
void HashTableInit(HT *ht,int IsLineDetetive)
{
	int i = 0;
	for (; i < MAX_SIZE; ++i)
		ht->_array[i]._state = EMPTY;
	ht->_IsLineDetective = IsLineDetetive;
	ht->_size = 0;
	ht->_total = 0;
}
//插入
void HashTableInsert(HT *ht, DataType data)
{
	int hashAddr = -1;
	int i = 0;
	assert(ht);
	if (ht->_total == MAX_SIZE)
		return;
	//计算哈希地址
	hashAddr = hashFunc(data);
	while (EMPTY != ht->_array[hashAddr]._state)//状态不为空
	{
		if (EXIST == ht->_array[hashAddr]._state)//状态为存在
		{
			if (data == ht->_array[hashAddr]._data)
				return;
		}
		//hashAddr++;//发生冲突后朝后走
	//	if (hashAddr == MAX_SIZE)//判断是否越界
	//		hashAddr = 0;//越界后跳转到为0的地址处,即从头开始找空位置
	}
	if (ht->_IsLineDetective)//线性探测
		DetectiveLine(hashAddr);
	else
		DetectiveLine2(hashAddr, ++i);//二次探测
	//插入元素
	ht->_array[hashAddr]._data = data;//插入数据
	ht->_array[hashAddr]._state = EXIST;//状态从空改为存在
	ht->_size++;
	ht->_total++;
}
int hashFunc(DataType data)
{
	return data%MAX_SIZE;
}
//删除
void HashTableDelete(HT *ht, DataType data)
{
	int ret = -1;
	assert(ht);
	ret = HashTableFind(ht, data);
	if (-1 != ret)
	{
		ht->_array[ret]._state = DELETE;
		ht->_size--;
	}
}
//查找
int HashTableFind(HT *ht, DataType data)
{
	int hashAddr = -1;
	int startAddr = -1;//开始查找的地址
	int i = 0;
	assert(ht);
	hashAddr = hashFunc(data);
	startAddr = hashAddr;
	while (ht->_array[hashAddr]._state != EMPTY)
	{
		if (EXIST == ht->_array[hashAddr]._state)
		{
			if (data == ht->_array[hashAddr]._data)
				return hashAddr;
		}
		//hashAddr++;//没有找到,继续往后找
		//if (hashAddr == MAX_SIZE)//越界了,从头再找
		//	hashAddr = 0;
		//if (hashAddr == startAddr)//哈希地址等于开始查找的起始地址,说明找了一圈都没有找到
		//	return -1;
		if (ht->_IsLineDetective)
		{
			DetectiveLine(hashAddr);
			//找了一圈没有找到
			if (hashAddr == startAddr)
				return -1;
		}
		else
			Detective2(hashAddr, ++i); 
	}
	return -1;//没有找到
}
//计算哈希表格中的元素个数
int HashTableSize(HT *ht)
{
	return ht->_size;
}
//判断哈希表格是不是空的
int HashTableEmpty(HT *ht)
{
	assert(ht);
	return 0 == ht->_size;
}
int DetectiveLine(int hashAddr)//线性探测
{
	hashAddr++;
	if (hashAddr == MAX_SIZE)
		hashAddr = 0;
	return hashAddr;
}
void Detective2(int hashAddr, int i)//二次探测
{
	hashAddr = hashAddr + 2 * i + 1;
	if (hashAddr >= MAX_SIZE)//越界了
		hashAddr %= MAX_SIZE;//越界之后模回来
	return hashAddr;
}

二次探测的缺点:
(1、是静态的
(2、不能存放字符串
(3、哈希函数用的除留余数法,除数不是素数
(4、什么时候增容
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xuruhua

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值