• 005.用哈希查找算法查找七色光颜色【哈希查找算法】


    1. 哈希查找算法

    哈希查找算法就是使用哈希函数来计算一个键值所对应的地址,进而建立哈希表格,然后利用哈希函数来查找到各个键值存放在表格中的地址。简单来说,就是把一些复杂的数据,通过某种函数映射(与数学中的映射关系一样)关系,映射成更易于查找的方式。哈希查找算法的查找速度与数据多少无关,完美的哈希查找算法一般都可以做到一次读取完成查找。

    哈希查找算法就是这样一种算法,例如,在一本书中查找内容,首先翻开这本书的目录,然后在目录上找到想要的内容,最后根据对应的页码就能找到所需要的内容。哈希查找算法具有保密性高的特点,因此哈希查找算法常被应用在数据压缩和加解密方面。常见的哈希算法有除留取余法、平方取中法以及折叠法。

    1.1 哈希表和哈希函数

    哈希表是一种存储键值和键值所对应地址的一种数据集合。哈希表中的位置,一般称为槽位,每个槽位都能保存一个数据元素并以一个整数命令(从0开始)。这样我们就有了0号槽位、1号槽位等。起始时,哈希表里没有数据,槽位是空的,这杨在构建哈希表时,可以把槽位的值都初始化成 None 。数据元素和保存的槽位之间的映射关系,称为哈希函数。哈希函数接受一个数据元素作为参数,返回一个0到n-1的整数作为槽位名。

    1.2 除留余数法

    除留余数法是哈希算法中最简单的一种算法。它是将每个数据除以某个常数后,取余数来当索引。除留取余法对应的哈希函数如下:

    h(item)=item % num
    
    • 1
    • item:每个数据
    • num:一个常数,一般会选择一个质数,例如取质数11

    1.3 折叠法

    对于给定的数据集,哈希函数将每个元素映射为单个槽位,称为 “完美哈希函数” 。但是对于任意一个数据集合,没有系统能构造出完美哈希函数

    数据哈希值
    5410
    264
    935
    176
    770
    319

    对应的哈希函数也得到了哈希值,例如:h(54)=10, h(26)=4, h(93)=5 等等。

    1.4 折叠法

    对于给定的数据集,哈希函数将每个元素映射为单个槽位,称为 “完美哈希函数”。但是对于任意一个数据集合,没有系统能够构造出完美哈希函数。例如,在上述除留取余的例子中再加上一个数据44,该数字除以11后,得到的余数是0,这与数据77的哈希值相同。遇到这种情况时,解决办法之一就是扩大哈希表,但是这种做法太浪费空间。因此又有了扩展除留取余的方案,也就是折叠法。

    折叠法是先将数据拆分成几组数据,再把他们加起来作为哈希地址,再使用除留取余法,这中做法称为“移动折叠法”。

    对奇数或偶数进行反转,再将反转后的数字相加,再使用除留取余法,这中做法称为“边界折叠法”。

    1.5 平方取中法

    平方取中法是先将各个数据平方,将平方后数据取中间的某段数字作为索引,例如,对于数据集 54,26,93,17,77,31, 平方取中法如下:

    • 先取平方:522 = 2916,262 = 676,…
    • 取以上平方值的中间数,即取十位和百位:91,67,…
    • 设置槽位11,分别除以11留余数,得到哈希值分别为:3,1,…

    2. 用哈希查找算法查找七色光颜色

    哈希算法理想的情况是所有数据经过哈希函数运算后得到不同的值,但是在实例情况中即使得到的哈希值不同,也有可能得到相同的地址,这种问题被称为 “碰撞问题”。使用哈希算法,将数据放到哈希表中存储数据对应位置,若该位置满了,就会溢出,这种问题被称为 “溢出问题”。(常见的处理方式后续再讲)

    class HashTable:                                                            # 创建哈希表
        def __init__(self):
            self.size = 11                                                      # 哈希表长度
            self.throw = [None] * self.size                                     # 哈希表数据键初始化
            self.data = [None] * self.size                                      # 哈希表数据值初始化
    
        # 假定最终将有一个空槽,除非 key 已经存在于  self. throw中。 它计算原始
        # 哈希值,如果该槽不为空,则迭代 rehash 函数,直到出现空槽。如果非空槽已经包含 key,
        # 则旧数据值将替换为新数据值。
        def put(self, key, value):                                              # 输出键值
            hashvalue = self.hashfunction(key, len(self.throw))                 # 创建哈希值
            if self.throw[hashvalue] is None:
                self.throw[hashvalue] = key                                     # 将key值给哈希表的throw
                self.data[hashvalue] = value                                    # 将value值给哈希表的data
            else:
                if self.throw[hashvalue] == key:
                   self.data[hashvalue] = value
    
                else:
                    nextslot = self.rehash(hashvalue, len(self.throw))
                    while self.throw[nextslot] is not None and self.throw[nextslot] != key:
                        nextslot = self.rehash(nextslot, len(self.throw))
    
                    if self.throw[nextslot] is None:
                        self.throw[nextslot] = key
                        self.data[nextslot] = value
                    else:
                        self.data[nextslot] = value
    
        # 重新加1,除以11,留余数
        def rehash(self, oldhash, size):
            return (oldhash + 1) % size
    
        # 除以11,留余数
        def hashfunction(self, key, size):
            return key % size
    
        # 从计算初始哈希值开始。如果值不在初始槽中,则 rehash 用
        # 于定位下一个可能的位置。
        def get(self, key):
            startslot = self.hashfunction(key, len(self.throw))
            data = None
            found = False
            stop = False
            pos = startslot
            while pos is not None and not found and not stop:
                if self.throw[pos] == key:
                    found = True
                    data = self.data[pos]
                else:
                    pos = self.rehash(pos, len(self.throw))
                    # 回到了原点,表示找遍了没有找到
                    if pos == startslot:
                        stop = True
            return data
    
        # 重载载 __getitem__ 和 __setitem__ 方法以允许使用 [] 访问
        def __getitem__(self, key):
            return self.get(key)
    
        def __setitem__(self, key, value):
            return self.put(key, value)
    
    
    # 创建哈希表、给哈希表赋值
    H = HashTable()
    H[16] = "红"
    H[28] = "橙"
    H[32] = "黄"
    H[14] = "绿"
    H[56] = "青"
    H[36] = "蓝"
    H[71] = "紫"
    
    
    print("key的数据是:",H.throw)           # 输出键key
    print("value的数据是:",H.data)          # 输出值value
    print("结果是:",H[28])                  # 根据key=28查value
    print("结果是:",H[71])                  # 根据key=71查value
    print("结果是:",H[93])                  # 根据key=93查value
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
  • 相关阅读:
    高考志愿填报和未来的职业规划
    建筑楼宇VR火灾扑灭救援虚拟仿真软件厂家
    云IDE产品测评报告
    java计算机毕业设计疫情防控管理系统MyBatis+系统+LW文档+源码+调试部署
    杭州某国企 Java 面经
    【实战技能】单片机bootloader的CANFD,I2C,SPI和串口方式更新APP视频教程(2022-08-01)
    MySQL基础——DDL、DML、DQL、DCL语句
    代码随想录算法训练营002| 59. 螺旋矩阵 II,209. 长度最小的子数组,977. 有序数组的平方
    vue中打印插件vue-print-nb(二)-实例之两种方法——安包之设置一个id和绑定一个对象 & 下载print.js之ref设置锚点
    shutdown的各类参数及用法
  • 原文地址:https://blog.csdn.net/qq_42226855/article/details/126665961