【数据结构3】哈希表、哈希表的应用(集合与字典、md5算法和文件的哈希值)

news2024/9/19 13:20:46

1 哈希表

哈希表一个通过哈希函数来计算数据存 储位置的数据结构,通常支持如下操作:
插入(键,值):插入键值对(键,值)
Get(key):如果存在键为键的键值对则返回其值,否则返回空值
删除():删除键为键的键值对

哈希表(Hash Table,又称为散列表),是一种线性表的存储结构。哈希表由一个直接寻址表和一个哈希函数组成。哈希函数h(k)将元素关键字k作为自变量,返回元素的存储下标。

解决哈希冲突使用:拉链法
拉链法:哈希表每个位置都连接一个链表,当冲突发生时,冲突的元素将被加到该位置链表的最后。

在这里插入图片描述

class LinkList:
    """
    单链表实现
    """

    # Node类表示链表中的一个节点
    class Node:
        def __init__(self, item=None):
            """
            初始化链表节点
            :param item: 节点存储的数据,默认为None
            """
            self.item = item  # 存储节点的数据
            self.next = None  # 指向下一个节点的指针,初始为None

    # LinkListIterator类用于实现链表的迭代器
    class LinkListIterator:
        def __init__(self, node):
            """
            初始化链表迭代器
            :param node: 链表的起始节点
            """
            self.node = node  # 保存当前节点,用于迭代

        def __next__(self):
            """
            获取链表中的下一个元素
            :return: 当前节点的数据
            :raises StopIteration: 如果没有更多节点,则停止迭代
            """
            if self.node:
                cur_node = self.node  # 保留当前节点
                self.node = cur_node.next  # 移动到下一个节点
                return cur_node.item  # 返回当前节点的数据
            else:
                raise StopIteration  # 如果没有更多节点,则停止迭代

        def __iter__(self):
            """
            返回迭代器对象自身
            :return: 迭代器对象自身
            """
            return self  # 返回迭代器对象自身,使其可以在for循环中使用

    def __init__(self, iterable=None):
        """
        初始化链表
        :param iterable: 可迭代对象,用于初始化链表的元素
        """
        self.head = None  # 链表头节点的引用,初始化为空
        self.tail = None  # 链表尾节点的引用,初始化为空
        if iterable:
            self.extend(iterable)  # 如果传入了可迭代对象,则扩展链表

    def append(self, obj):
        """
        在链表末尾添加一个新节点
        :param obj: 要添加的元素
        """
        s = LinkList.Node(obj)  # 创建一个新节点
        if not self.head:
            self.head = s  # 如果链表为空,将头节点和尾节点都指向新节点
            self.tail = s
        else:
            self.tail.next = s  # 将当前尾节点的next指针指向新节点
            self.tail = s  # 更新尾节点为新节点

    def extend(self, iterable):
        """
        扩展链表,将可迭代对象中的每个元素添加到链表中
        :param iterable: 可迭代对象
        """
        for obj in iterable:
            self.append(obj)  # 依次添加可迭代对象中的每个元素

    def find(self, obj):
        """
        查找链表中是否存在指定的元素
        :param obj: 要查找的元素
        :return: 如果找到目标元素,则返回True;否则返回False
        """
        for n in self:
            if n == obj:
                return True  # 如果找到了目标元素,返回True
        return False  # 如果遍历结束也没有找到目标元素,返回False

    def delete(self, obj):
        """
        从链表中删除指定的元素
        :param obj: 要删除的元素
        :return: 如果成功删除,返回True;否则返回False
        """
        current = self.head  # 当前节点,初始化为链表的头节点
        previous = None  # 前一个节点的引用,初始化为None
        while current:
            if current.item == obj:
                if previous:
                    previous.next = current.next  # 跳过当前节点
                else:
                    self.head = current.next  # 如果删除的是头节点,更新头节点
                if current == self.tail:
                    self.tail = previous  # 如果删除的是尾节点,更新尾节点
                return True  # 删除成功
            previous = current
            current = current.next
        return False  # 如果没有找到目标元素,返回False

    def __iter__(self):
        """
        返回链表的迭代器对象
        :return: 链表的迭代器对象
        """
        return self.LinkListIterator(self.head)  # 返回一个迭代器对象,从头节点开始迭代

    def __repr__(self):
        """
        返回链表的字符串表示形式
        :return: 链表的字符串表示形式,格式为"<<" + 元素 + ">>"
        """
        return "<<" + ",".join(map(str, self)) + ">>"  # 返回链表的字符串表示形式,元素之间用逗号分隔,整体用"<<"和">>"包围


# lk = LinkList([1, 2, 3, 4, 5])
# print(lk)
# for element in lk:
#     print(element)

class HashTable:
    """
    哈希表实现
    """

    def __init__(self, size=101):
        self.size = size  # 哈希表的大小
        self.T = [LinkList() for _ in range(self.size)]  # 初始化哈希表数组,每个位置是一个链表

    def h(self, k):
        """
        哈希函数,将键k映射到表中的索引位置
        """
        return k % self.size  # 计算哈希值

    def insert(self, k):
        """
        插入一个键到哈希表中
        """
        i = self.h(k)  # 计算键的哈希值,确定插入位置
        if self.find(k):
            print('重复插入')  # 如果键已存在,打印提示
        else:
            self.T[i].append(k)  # 将键插入到相应位置的链表中
            print(f'{k}插入成功')  # 插入成功提示

    def find(self, k):
        """
        查找哈希表中是否存在指定的键
        """
        i = self.h(k)  # 计算键的哈希值,确定查找位置
        return self.T[i].find(k)  # 在链表中查找键

    def delete(self, k):
        """
        从哈希表中删除指定的键
        """
        i = self.h(k)  # 计算键的哈希值,确定删除位置
        if self.T[i].delete(k):
            print(f'{k}删除成功')  # 删除成功提示
        else:
            print(f'{k}未找到')  # 如果键不存在,打印提示


# 使用示例
lk = HashTable()
lk.insert(1)
lk.insert(2)
lk.insert(3)
print(lk.find(2))  # 输出: True
print(lk.find(4))  # 输出: False
lk.delete(2)  # 删除键2
print(lk.find(2))  # 输出: False

2 哈希表的应用-集合与字典

字典与集合都是通过哈希表来实现的。
a={'name': 'Alex', 'age':18, 'gender': 'an'}
使用哈希表存储字典,通过哈希函数将字典的键映射为下标。
	假设h('name')=3,h('age')=1,h('gender')= 4,则哈希表存储为[None, 18,None,'Alex''Man']
如果发生哈希冲突,则通过拉链法或开发寻址法解决

3 哈希表的应用-md5算法和文件的哈希值

MD5(Message-Digest Algorithm 5)曾经是密码学中常用的哈希函数,可以把任意长度的数据映射为128 位的哈希值。
其曾经包含如下特征:
1.同样的消息,其MD5值必定相同;
2.可以快速计算出任意给定消息的MD5值:
3.除非暴力的枚举所有可能的消息,否则不可能从哈 希值反推出消息本身;
4.两条消息之间即使只有微小的差别,其对应的MD5 值也应该是完全不同、完全不相关的;
5.不能在有意义的时间内人工的构造两个不同的消息 使其具有相同的MD5值。

应用举例:文件的哈希值
算出文件的哈希值,若两个文件的哈希值相同,则可认为这两个文件是相同的。
因此:
1.用户可以利用它来验证下载的文件是否完整
2.云存储服务商可以利用它来判断用户要上传的文件 是否已经存在于服务么器上,
	从而实现秒传的功能,同时避免存储过多相同的文件副本。

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

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

相关文章

数据仓库系列 2:数据仓库的核心特点是什么?

想象一下,你正站在一座巨大的数据金矿前。这座金矿蕴含着海量的商业洞察,可以帮助你的公司做出精准决策,提升效率,远超竞争对手。但是,如何高效地开采、提炼和利用这些数据黄金呢?答案就是:数据仓库。 目录 什么是数据仓库?数据仓库的核心特点面向主题的组织集成性非易失性…

RTL-SDR SpectrumPy频谱显示

GITHUB大佬开源的基于RTL-SDR的python频谱显示程序链接&#xff0c;下载下来后&#xff0c;安装必要的库&#xff0c;编译运行&#xff0c;运行报错。 修改了以下两个地方&#xff1a; 修改点1&#xff1a; 修改前&#xff1a; self.spinBoxFrequency.setValue(self.center_fr…

【Python从入门到进阶】63.Pandas如何实现数据的Merge

接上篇《62、Pandas中DataFrame对象案例实践》 上一篇我们延续之前学习的DataFrame对象的知识&#xff0c;结合一个数据案例进行了实践操作。本篇我们来学习Pandas如何实现数据的Merge。 一、引言 在当今数据驱动的时代&#xff0c;数据分析已成为各行各业不可或缺的一部分。…

【JAVA基础】四则运算符

文章目录 四则运算结合运算符自增运算符关系和boolean运算符 四则运算 在java当中&#xff0c;使用运算符、-、*、/ 表示加减乘除&#xff0c;当参与 / 运算的两个操作数都是整数的时候&#xff0c;表示整数除法&#xff1b;否则表示浮点数。整数的求余操作用 % 表示。 Syste…

【Java】/* 与树有关的一些概念 */

一、关于树的一些概念 1. 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看 起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。它具有以下的特点&#xff1a;…

记录一次经历:使用flask_sqlalchemy集成flask造成循环导入问题

前言&#xff1a; 工作需求&#xff0c;写一个接口&#xff0c;用Python来编写&#xff0c;我首先想到用flask小型框架来支撑&#xff0c;配置sqlalchemy来实现&#xff0c;但是在实现的过程中&#xff0c;发生循环导入问题 我想到用蓝图来解决此问题&#xff0c;但是仍然会出死…

UI测试使用webdriver-manager免安装浏览器驱动

引言&#xff1a; selenium传统的方式是下载浏览器对应的driver&#xff08;驱动&#xff09;&#xff0c;放到本地的指定位置&#xff0c;然后写代码加载这个driver&#xff08;驱动&#xff09;再执行相应的操作。 弊端&#xff1a; 传统方法存在两个麻烦的地方: 1.需要下…

安全面试常见问题任意文件下载

《网安面试指南》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484339&idx1&sn356300f169de74e7a778b04bfbbbd0ab&chksmc0e47aeff793f3f9a5f7abcfa57695e8944e52bca2de2c7a3eb1aecb3c1e6b9cb6abe509d51f&scene21#wechat_redirect 1.1 任意文件下…

Git的使用教程及常用语法03

七.如何从版本库中删除文件 第一种方式&#xff1a;直接在工作区删除文件&#xff0c;然后提交 rm ffile1.txt (注意&#xff1a;这个不是git命令&#xff0c;而是linux命令) 看到状态发现&#xff0c;文件file1.txt已经被删除&#xff0c;提示需要提交到暂存区。 因为我们只…

蓝牙对象交换协议(OBEX) - 概念介绍

零.声明 本专栏文章我们会以连载的方式持续更新&#xff0c;本专栏计划更新内容如下&#xff1a; 第一篇:蓝牙综合介绍 &#xff0c;主要介绍蓝牙的一些概念&#xff0c;产生背景&#xff0c;发展轨迹&#xff0c;市面蓝牙介绍&#xff0c;以及蓝牙开发板介绍。 第二篇:Trans…

SpringBoot集成kafka-监听器注解

SpringBoot集成kafka-监听器注解 1、application.yml2、生产者3、消费者4、测试类5、测试 1、application.yml #自定义配置 kafka:topic:name: helloTopicconsumer:group: helloGroup2、生产者 package com.power.producer;import com.power.model.User; import com.power.uti…

Windows系统上进行项目管理工具VisualSVN Server服务端的保姆级安装教程与配置和SVN客户端保姆级安装教程和使用

一、VisualSVN Server简介 Subversion Server for Windows | VisualSVN ServerGet an easy to use Subversion (SVN) server for Windows. It works out-of-the-box and is suitable both for small business and enterprises. Available for free!https://www.visualsvn.com/…

4.Redis单线程和多线程

1.Redis的单线程 Redis的单线程主要是指Redis的网络IO和键值对读写是由一个线程完成的&#xff0c;Redis在处理客户端的请求时包括获取&#xff08;Socket读&#xff09;、解析、执行、内容返回&#xff08;Socket写&#xff09;等都由一个顺序串行的主线程处理&#xff0c;这…

Linux 下命令行参数和环境变量

Linux 下命令行参数和环境变量 命令行参数为什么要有命令行参数谁可以做到结论 环境变量一些现象查看环境变量添加环境变量添加内存级环境变量永久有效 其他环境变量HOMEPWDSHELLHISTSIZE 自定义环境变量定义取消 本地变量整体理解环境变量环境变量的组织方式Linux 代码获取环境…

SpringBoot集成kafka接收对象消息

SpringBoot集成kafka接收对象消息 1、生产者2、消费者3、工具类4、消息实体对象5、配置文件6、启动类7、测试类8、测试结果 1、生产者 package com.power.producer;import com.power.model.User; import com.power.util.JSONUtils; import org.springframework.kafka.core.Kaf…

UEStudio V24 中文授权版

UEStudio是一款集成开发环境&#xff08;IDE&#xff09;软件&#xff0c;主要用于编写和编辑各种类型的代码&#xff0c;包括C/C、Java、HTML、PHP、Perl、Python等。 软件截图&#xff1a; 使用说明&#xff1a; 解压后&#xff0c;双击start_UEStudio.bat来运行软件 下载地…

【计算机组成原理】计算机系统概述<1>

学习目标&#xff1a; 掌握计算机组成原理的基础知识巩固 例如&#xff1a; 信息化世界的组成 计算机系统概述 计算机硬件基本组成 各个硬件的工作原理 计算机软件 计算机系统的多层次结构 计算机系统的工作原理 计算机性能指标 学习内容&#xff1a; 1.0、初入计算机组成原…

Apollo9.0 PNC源码学习之Planning模块—— Lattice规划(七):横纵向运动轨迹的优选

参考文章: (1)Apollo6.0代码Lattice算法详解——Part 7: 获得最优轨迹 (2)Lattice算法详解 0 前言 // 优选出cost最小的trajectory// 7. always get the best pair of trajectories to combine; return the first// collision-free trajectory.size_t constraint_failure…

Latent-OFER:使用潜在向量进行检测、屏蔽和重建,以实现遮挡的面部表情识别

论文&#xff1a;Latent-OFER: Detect, Mask, and Reconstruct with Latent Vectors for Occluded Facial Expression Recognition 摘要&#xff1a;所提出的方法Latent-OFER可以检测遮挡&#xff0c;将面部被遮挡的部分恢复为未被遮挡的部分&#xff0c;并识别它们&#xff0…

【Java自动化学习】Web自动化

一、环境安装 环境搭建安装见此博客文章链接&#xff1a;https://blog.csdn.net/qq_73471456/article/details/130836494 二、元素定位、等待方式 见此之前的博客文章&#xff1a;selenium操作使用方式 三、下拉框定位 四、iframe 切换元素定位 注意事项&#xff1a;连续定…