哈希表与哈希扩容

news2024/11/28 19:03:46

一,哈希表

哈希表简单的理解:在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应。 

哈希表基于数组的,正因为数组创建后难于扩展某些哈希表被基本填满时,性能下降得非常严重,所以程序虽必须要清楚表中将要存储多少数据(或者准备好定期地把数据转移到更大的哈希表中,这是个费时的过程)

如何定位数据存储的位置呢?

h(key) = key % size

1.线性哈希表

线性哈希表可以认为就是数组,不过他对数据的存储方式不如线性表一般按顺序来,他是通过某种算法来计算得到数据下标值的。可以想象如果数据比较多,那么重下标的情况会很多,所以就有了哈希冲突。

代码实现

class Array():
    def __init__(self,size):
        self.__size = size
        self.__item = [None]*size
        self.__length = 0

    def __setitem__(self,key,value):
        self.__item[key] = value
        self.__length += 1

    def __getitem__(self, index):
        return self.__item[index]

    def __len__(self):
        return self.__length

    def __iter__(self):
        for value in self.__item:
            yield value

class Slot():
    def __init__(self,key,value):
        self.key = key
        self.value = value

    def __str__(self):
        return 'key:{}  value:{}'.format(self.key,self.value)


class HashTable():
    def __init__(self):
        self.size = 4
        self.items = Array(self.size)



    def find_index_to_insert(self,key):
        index = self.get_index(key)
        if self.items[index] == None:
            return index
        else:
            while self.items[index] is not None:
                if self.items[index].key == key:
                    return index
                else:
                    index = (5*index+1) % self.size
            return index

    def find_key(self,key):
        index = self.get_index(key)
        if self.items[index] == None:
            return None
        else:
            while self.items is not None:
                if key == self.items[index].key:
                    return index
                else:
                    index = (5*index+1) % self.size
            return None


    def get_index(self,key):
        return hash(key) % self.size

    def put(self, key, value):
        s = Slot(key, value)
        index = self.find_index_to_insert(key)
        self.items[index] = s


    def get(self,key):
        index = self.get_index(key)
        return self.items[index]


if __name__ == '__main__':
    h = HashTable()
    h.put('name','L')
    h.put('sex','M')
    h.put('age','18')
    h.put('occupation','general')
    print(h.get('name'))
    print(h.get('sex'))
    print(h.get('age'))
    print(h.get('occupation'))


2.链式哈希表

链式哈希表可以认为是数组,不过数组内的元素是链表,有种线性表嵌套链式表的既视感,者带来的好处就多了:不仅拥有了更好的空间利用率,同时解决了哈希冲突的问题:即使出现重下标的情况,我们也可以顺着往下加,之后顺着表一个一个找就可以了。

当然对链表的处理也可以改成双向链表,不过感觉没太大必要。 

代码实现

class Array():
    def __init__(self,size):
        self.__size = size
        self.__item = [None]*size
        self.__length = 0

    def __setitem__(self,key,value):
        self.__item[key] = value
        self.__length += 1

    def __getitem__(self, index):
        return self.__item[index]

    def __len__(self):
        return self.__length

    def __iter__(self):
        for value in self.__item:
            yield value

class Slot():
    def __init__(self,key,value,next=None):
        self.key = key
        self.value = value
        self.next = next

    def __str__(self):
        return 'key:{}  value:{}'.format(self.key,self.value)


class HashTable():
    def __init__(self):
        self.size = 4
        self.items = Array(self.size)


    def get_index(self,key):
        return hash(key) % self.size

    def put(self, key, value):
        s = Slot(key, value)
        index = self.get_index(key)
        if self.items[index] == None:
            self.items[index] = s
        else:
            if self.items[index].key == key:
                self.items[index].value = value
            else:
                temp = self.items[index]
                temp_next = self.items[index].next
                while temp_next is not None:
                    if temp_next.key == key:
                        temp_next.value = value
                        return
                    else:
                        temp = temp_next
                        temp_next = temp.next
                temp.next = s


    def get(self,key):
        index = self.get_index(key)
        if self.items[index]:
            if self.items[index].key == key:
                return self.items[index]
            else:
                temp_next = self.items[index].next
                while temp_next is not None:
                    if temp_next.key == key:
                        return temp_next
                    else:
                        temp_next = temp_next.next
                return None

if __name__ == '__main__':
    h = HashTable()
    h.put('name','L')
    h.put('sex','M')
    h.put('age','18')
    h.put('occupation','general')
    print(h.get('name'))
    print(h.get('sex'))
    print(h.get('age'))
    print(h.get('occupation'))




二,哈希扩容

装载因子(load factor)

如果继续往我们的哈希表里塞东西会发生什么?空间不够用。这里我们定义一个负载因子的概念(load factor),其实很简单,就是已经使用的槽数比哈希表大小。 比如我们上边的例子插入了 8 个元素,哈希表总大小是 13, 它的 load factor 就是 $ 8/13 \approx 0.62 $。当我们继续往哈希表插入数据的时候,很快就不够用了。 通常当负载因子开始超过 0.8 的时候,就要新开辟空间并且重新进行散列了。

重哈希(Rehashing)

当负载因子超过 0.8 的时候,需要进行 rehashing 操作了。步骤就是重新开辟一块新的空间,开多大呢?感兴趣的话可以看下 cpython 的 dictobject.c 文件然后搜索 GROWTH_RATE 这个关键字,你会发现不同版本的 cpython 使用了不同的策略。python3.3 的策略是扩大为已经使用的槽数目的两倍。开辟了新空间以后,会把原来哈希表里 不为空槽的数据重新插入到新的哈希表里,插入方式和之前一样。这就是 rehashing 操作。

代码实现

class Array():
    def __init__(self,size):
        self.__size = size
        self.__item = [None]*size
        self.__length = 0

    def __setitem__(self,key,value):
        self.__item[key] = value
        self.__length += 1

    def __getitem__(self, index):
        return self.__item[index]

    def __len__(self):
        return self.__length

    def __iter__(self):
        for value in self.__item:
            yield value

class Slot():
    def __init__(self,key,value):
        self.key = key
        self.value = value

    def __str__(self):
        return 'key:{}  value:{}'.format(self.key,self.value)


class HashTable():
    def __init__(self):
        self.size = 4
        self.length = 0
        self.items = Array(self.size)



    def find_index_to_insert(self,key):
        index = self.get_index(key)
        if self.items[index] == None:
            return index
        else:
            while self.items[index] is not None:
                if self.items[index].key == key:
                    return index
                else:
                    index = (5*index+1) % self.size
            return index

    def find_key(self,key):
        index = self.get_index(key)
        if self.items[index] == None:
            return None
        else:
            while self.items is not None:
                if key == self.items[index].key:
                    return index
                else:
                    index = (5*index+1) % self.size
            return None


    def get_index(self,key):
        return hash(key) % self.size

    def put(self, key, value):
        s = Slot(key, value)
        index = self.find_index_to_insert(key)
        self.items[index] = s
        self.length += 1
        if self.load_factor():
            self.rehashing()


    def load_factor(self):
        return self.length / float(self.size) > 0.8

    def rehashing(self):
        self.length = 0
        old = self.items
        self.size = self.size << 1
        self.items = Array(self.size)
        for s in old:
            if s:
                key = s.key
                index = self.find_index_to_insert(key)
                self.items[index] = s
                self.length += 1

    def get(self,key):
        index = self.get_index(key)
        return self.items[index]

if __name__ == '__main__':
    h = HashTable()
    h.put('name', 'L')
    h.put('sex', 'M')
    h.put('age', '18')
    h.put('occupation', 'general')
    h.put('occupation1', 'general')
    h.put('occupation2', 'general')
    h.put('occupation3', 'general')
    h.put('occupation5', 'general')
    h.put('occupation6', 'general')
    print(h.get('name'))
    print(h.get('sex'))
    print(h.get('age'))
    print(h.get('occupation'))
    print(h.get('occupation1'))
    print(h.get('occupation2'))
    print(h.get('occupation3'))
    print(h.get('occupation5'))

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

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

相关文章

【SQLAlChemy】怎么进行简单的增删改查,CRUD操作是什么?

CRUD 所有的 CRUD 操作&#xff0c;必须在 session 的前提下进行。 构建 session 对象(实例) 所有和数据库的 ORM 操作都必须通过一个叫做 session 的会话对象来实现。 from sqlalchemy.orm import sessionmaker# 构建 session 对象 # engine 为之前创建的数据库连接引擎 s…

透视亚马逊云科技中国峰会:生成式AI全面提速,加速行业应用落地

导读&#xff1a;亚马逊云科技在中国&#xff0c;生成式AI与行业化战略齐头并进。 “亚马逊云科技致力于成为企业构建和应用生成式AI的首选。” 近日2024亚马逊云科技中国峰会上&#xff0c;亚马逊全球副总裁、亚马逊云科技大中华区总裁储瑞松分享了亚马逊云科技中国业务最新进…

Maven核心功能依赖和构建管理

1.依赖管理和配置 Maven 依赖管理是 Maven 软件中最重要的功能之一。Maven 的依赖管理能够帮助开发人员自动解决软件包依赖问题&#xff0c;使得开发人员能够轻松地将其他开发人员开发的模块或第三方框架集成到自己的应用程序或模块中&#xff0c;避免出现版本冲突和依赖缺失等…

【Python机器学习】NMF——模拟数据

与使用PCA不同&#xff0c;我们需要保证数据是正的&#xff0c;NMF能够对数据进行操作。这说明数据相对于原点(0,0)的位置实际上对NMF很重要。因此&#xff0c;可以将提取出来的非负向量看作是从(0,0)到数据的方向。 举例&#xff1a;NMF在二维玩具数据上的结果&#xff1a; …

SSH反向代理

介绍 SSH反向代理是一种通过SSH协议实现的安全远程访问方式。在这种方式中&#xff0c;客户端通过SSH连接到一台具有公网IP的主机&#xff0c;然后这台主机再将请求转发给内部网络中的目标主机。这样做的好处是可以隐藏内部网络的细节&#xff0c;提高安全性&#xff0c;同时也…

Docker搭建可道云

Docker搭建可道云&#xff08;存储&#xff09; 文章目录 Docker搭建可道云&#xff08;存储&#xff09;介绍资源列表基础环境一、安装Docker二、配置Docker加速器三、搭建可道云私有云盘3.1、编写Dockerfile3.2、上传资源到指定目录3.3、查看目录下所有资源 四、构建镜像五、…

易于上手的requests

Python中的requests库主要用于发送HTTP请求并获取响应结果。在现代网络编程中&#xff0c;HTTP请求是构建客户端与服务器之间通信的基础。Python作为一种高级编程语言&#xff0c;其丰富的库支持使得它在网络数据处理领域尤为突出。其中&#xff0c;requests库以其简洁、易用的…

C# 绘图及古诗填字

绘图 绘图的结果如下&#xff1a; 绘图部分主要使用了 Bitmap、Graphics 具体的函数是 MakeMap 入参说明 string bg : 背景图 Rectangle rect &#xff1a;绘图区域 int row_count &#xff1a;行数 int col_count &#xff1a;列数 string fn &#xff1a;保存到的文件 …

HTML+CSS+JS 密码灯登录表单

效果演示 实现了一个登录页面,包括一个标题、两个输入框(用户名和密码)、一个登录按钮和一个眼睛图标。点击眼睛图标可以显示或隐藏密码。页面背景有两个圆形的半透明元素,整个页面使用了flex布局,并且在水平和垂直方向上都居中对齐。登录框使用了阴影效果和圆角边框,并且…

Django 表里做删除

先看效果图 点击 删除 按钮之后&#xff0c;就可以下面的效果 操作步骤&#xff1a; 1. 在 urls.py 文件里&#xff0c;添加路劲&#xff1a; urlpatterns [path(asset/<int:aid>/delete/, am_views.asset_delete),]2. 在 views.py 文件里&#xff0c;实现一个新的函…

【CS.AL】八大排序算法 —— 快速排序全揭秘:从基础到优化

文章目录 1. 快速排序简介1.1 定义1.2 时间复杂度1.3 相关资源 2. 最优的Partition算法 &#x1f525;2.1 Introsort简介2.2 过程示例 3. 非递归快速排序3.1 实现 4. 递归快速排序4.1 实现 5. 有问题的Partition5.1 实现 6. 三中位数主元选择6.1 实现 7. 总结 1. 快速排序简介 …

微信小程序基础工作模板

1.轮播图 点击跳转官方文档 简单例子 <!-- 顶部轮播图 --> <swiper indicator-dots"true" class"banner" autoplay"true" interval"2000"><swiper-item><image src"../../images/轮播图1.jpg" >…

Chrome跳转新的标签页自动打开控制台设置方法

Chrome跳转新的标签页自动打开控制台设置方法 文章目录 Chrome跳转新的标签页自动打开控制台设置方法1. 首先打开控制台2. 点击设置3. 选择Preferences -> Global -> 选中 Auto-open DevTools for popups4. 回到控制台勾选 preserve log保留日志![请添加图片描述](https:…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《基于状态分解的综合能源系统完全分布式调度算法》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

Flask 学习笔记 总结

python基础 服务端开发编程 第一个是赋值运算&#xff0c;第二是乘法&#xff0c;最后是一个是幂&#xff08;即a2&#xff09; a 2 a * 2 a ** 2 Python支持多重赋值&#xff1a; a, b, c 2, 3, 4 这句命令相当于&#xff1a; a 2 b 3 c 4 Python支持对字符串的灵活…

R语言数据探索和分析23-公共物品问卷分析

第一次实验使用最基本的公共物品游戏&#xff0c;不外加其他的treatment。班里的学生4人一组&#xff0c;一共44/411组。一共玩20个回合的公共物品游戏。每回合给15秒做决定的时间。第十回合后&#xff0c;给大家放一个几分钟的“爱心”视频&#xff08;链接如下&#xff09;&a…

Java 习题集

&#x1f496; 单选题 &#x1f496; 填空题 &#x1f496; 判断题 &#x1f496; 程序阅读题 1. 读代码写结果 class A {int m 5;void zengA(int x){m m x;}int jianA(int y){return m - y;} }class B extends A {int m 3;int jianA(int z){return super.jianA(z) m;} …

论文降痕指南:如何有效降低AIGC率

随着 AI 技术迅猛发展&#xff0c;各种AI辅助论文写作的工具层出不穷&#xff01; 为了防止有人利用AI工具进行论文代写&#xff0c;在最新的学位法中已经明确规定“已经获得学位者&#xff0c;在获得该学位过程中如有人工智能代写等学术不端行为&#xff0c;经学位评定委员会…

社区物资交易互助平台的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;基础数据管理&#xff0c;论坛管理&#xff0c;公告信息管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;论坛&#xff0c;求助留言板&#xff0c;公…

每日两题6

文章目录 删除并获得点数粉刷房子 删除并获得点数 分析 class Solution { public:int deleteAndEarn(vector<int>& nums) {const int N 10001;// 预处理int arr[N] {0};for (int& e : nums)arr[e] e;// 在 arr 上进行 打家劫舍 问题vector<int> f(N),…