python散列表实现查找,使用了多种算法并测试对比进行了性能分析(查找效率)

简介: 散列表实现查找本章是填补之前文章的坑,对哈希算法进行了实现,使用了平方取中法/除留余数法进行哈希映射,使用开放地址与公共溢出区解决冲突,同时对不同方法进行了性能分析对比,最后进行了总结。可以转载,但请声明源链接:文章源链接justin3go.com(有些latex公式某些平台不能渲染可查看这个网站)

散列表实现查找

本章是填补之前文章的坑,对哈希算法进行了实现,使用了平方取中法/除留余数法进行哈希映射,使用开放地址与公共溢出区解决冲突,同时对不同方法进行了性能分析对比,最后进行了总结。

可以转载,但请声明源链接:文章源链接justin3go.com(有些latex公式某些平台不能渲染可查看这个网站)

Library



import pandas as pd
import numpy as np
import time

读取数据


df = pd.read_excel('重庆市印刷和记录媒介复制业754.xlsx')
df.dropna(axis=0, how='any')  # 去除非数
print("表长为:", len(df))
df.head()
表长为: 75

image.png

get_nms


def get_nums(s):
    '''
    逐位相加其ASCII码
    '''
    s = str(s)
    nums = 0
    for s0 in s:
        if(s0 == '-'):
            continue
        try:
            nums += ord(s0)
        except:
            print("error: ",s)
    return nums
get_nums("重庆优得利印刷有限公司")


276879


平方取中法


df['nums_电话'] = df['电话'].apply(get_nums)
df['nums_电话^2'] = df['nums_电话'].apply(lambda x: np.square(x))
df['nums_企业名称'] = df['企业名称'].apply(get_nums)
# df['nums_电话^4'] = df['nums_电话^2'].apply(lambda x: np.square(x))
df.head()


image.png

def get_mid(x):
    '''
    取中间三位数作为地址
    '''
    return int(x/10)%1000


df['adr_电话'] = df['nums_电话^2'].apply(get_mid)
df['adr_企业名称'] = df['nums_企业名称'].apply(get_mid)
df.head(100)


image.png

image.png

除留余数法


df['adr_电话_1'] = df['nums_电话^2']%1007
df['adr_企业名称_1'] = df['nums_企业名称']%1007
df.head()

image.png

创建哈希表(分别使用开发地址与公共溢出区解决冲突)


#初始化为全0
# 开放地址法所使用的hash
hash_map_tele = np.zeros(32000)
hash_map_name = np.zeros(8000)
# 公共溢出区所使用的hash
hash_map_tele_1 = np.zeros(2100)
hash_map_name_1 = np.zeros(2100)
len(hash_map_tele)


400000
#探测开放地址法
def create_hash_map_tele(x, adr, df_ID):
    try:
        adr = int(x[adr])
    except:
        print('error: ', adr)
    while(hash_map_tele[adr] != 0):
        adr += 800
    hash_map_tele[adr] = x[df_ID]
def create_hash_map_name(x, adr, df_ID):
    try:
        adr = int(x[adr])
    except:
        print('error: ', adr)
    while(hash_map_name[adr] != 0):
        adr += 800
    hash_map_name[adr] = x[df_ID]
#使用公共溢出区
count1 = 0
count2 = 0
def create_hash_map_tele1(x, adr, df_ID):
    global count1
    if(hash_map_tele_1[x[adr]] == 0):
        hash_map_tele_1[x[adr]] = x[df_ID]
    else:
        hash_map_tele_1[1100 + count1] = x[df_ID]
        count1 += 1
def create_hash_map_name1(x, adr, df_ID):
    global count2
    if(hash_map_name_1[x[adr]] == 0):
        hash_map_name_1[x[adr]] = x[df_ID]
    else:
        hash_map_name_1[1100 + count2] = x[df_ID]
        count2 += 1


df.apply(create_hash_map_tele, axis=1, args=('adr_电话', 'ID'))
df.apply(create_hash_map_name, axis=1, args=('adr_企业名称', 'ID'))
df.apply(create_hash_map_tele1, axis=1, args=('adr_电话_1', 'ID'))
df.apply(create_hash_map_name1, axis=1, args=('adr_企业名称_1', 'ID'))
hash_map_tele


array([0., 0., 0., ..., 0., 0., 0.])

查找流程(平方取中+开发地址探测法)-method1


# 查找
search_method = int(input("请输入你查找关键词的类型:1,电话查找;2,企业名称查找"))
if(search_method == 1):
    tele = input("请输入你要查找对象的电话号码:")
    tele = int(tele)
    time_start = time.time()
    nums = get_mid(pow(get_nums(tele), 2))
    print("-----base_nums-----\n",nums)
    print("-----hash_map_tele_value-----\n", hash_map_tele[nums])
    print("-----开始查找-----")
    while(df['电话'][hash_map_tele[nums]] != tele):
        # print("-----tele-----\n", df['电话'][hash_map_tele[nums]])
        nums += 800
        # print('-----add_nums-----\n', nums)
        if(nums >= 32000):
            print('查找错误:无该信息')
            break
    time_end = time.time()
    if(nums < 32000):
        print("---------------你查找的信息如下:---------------\n", df.loc[hash_map_tele[nums]])
    print("---------------本次查找耗时:---------------\n",time_end-time_start)
elif(search_method == 2):
    name = input("请输入你要查找对象的企业名称:")
    time_start = time.time()
    nums = get_mid(get_nums(name))
    print("-----base_nums-----\n",nums)
    print("-----hash_map_tele_value-----\n", hash_map_name[nums])
    print("-----开始查找-----")
    while(df['企业名称'][hash_map_name[nums]] != name):
        # print("-----tele-----\n", df['企业名称'][hash_map_name[nums]])
        nums += 800
        # print('-----add_nums-----\n', nums)
        if(nums >= 8000):
            print('查找错误:无该信息')
            break
    time_end = time.time()
    if(nums < 8000):
        print("---------------你查找的信息如下:---------------\n", df.loc[hash_map_name[nums]])
    print("---------------本次查找耗时:---------------\n",time_end-time_start)
else:
    print("请选择正确的查找方式!")


-----base_nums-----
 370
-----hash_map_tele_value-----
 4.0
-----开始查找-----
---------------你查找的信息如下:---------------
 ID                          4
企业名称                      吕兴华
电话                13896015224
企业地址         重庆市璧山区大路街道天星街23号
nums_电话                   569
nums_电话^2              323761
adr_电话                    376
nums_企业名称               63703
adr_企业名称                  370
Name: 4, dtype: object
---------------查找耗时:---------------
 0.0009999275207519531


查找流程(除留余数法+公共溢出法)-method2


# 查找
search_method = int(input("请输入你查找关键词的类型:1,电话查找;2,企业名称查找"))
if(search_method == 1):
    tele = input("请输入你要查找对象的电话号码:")
    tele = int(tele)
    time_start = time.time()
    nums = get_nums(tele)%1007
    print("-----base_nums-----\n",nums)
    print("-----hash_map_tele_value-----\n", hash_map_tele_1[nums])
    print("-----开始查找-----")
    while(df['电话'][hash_map_tele_1[nums]] != tele):
        # print("-----tele-----\n", df['电话'][hash_map_tele_1[nums]])
        nums += 1
        # print('-----add_nums-----\n', nums)
        if(nums >= 2100):
            print('查找错误:无该信息')
            break
    time_end = time.time()
    if(nums < 2100):
        print("---------------你查找的信息如下:---------------\n", df.loc[hash_map_tele_1[nums]])
    print("---------------本次查找耗时:---------------\n",time_end-time_start)
elif(search_method == 2):
    name = input("请输入你要查找对象的企业名称:")
    time_start = time.time()
    nums = get_nums(name)%1007
    print("-----base_nums-----\n",nums)
    print("-----hash_map_tele_value-----\n", hash_map_name_1[nums])
    print("-----开始查找-----")
    while(df['企业名称'][hash_map_name_1[nums]] != name):
        # print("-----tele-----\n", df['企业名称'][hash_map_name_1[nums]])
        nums += 1
        # print('-----add_nums-----\n', nums)
        if(nums >= 2100):
            print('查找错误:无该信息')
            break
    time_end = time.time()
    if(nums < 2100):
        print("---------------你查找的信息如下:---------------\n", df.loc[hash_map_name_1[nums]])
    print("---------------本次查找耗时:---------------\n",time_end-time_start)
else:
    print("请选择正确的查找方式!")


-----base_nums-----
 262
-----hash_map_tele_value-----
 4.0
-----开始查找-----
---------------你查找的信息如下:---------------
 ID                           4
企业名称                       吕兴华
电话                 13896015224
企业地址          重庆市璧山区大路街道天星街23号
nums_电话                    569
nums_电话^2               323761
nums_企业名称                63703
adr_电话                     376
adr_企业名称                   370
adr_电话_1                   514
adr_企业名称_1                 262
Name: 4, dtype: object
---------------本次查找耗时:---------------
 0.005001544952392578


性能分析


df.head(10)


image.png

image.png

print("表长为:", len(df))


表长为: 754


32000与8000的来历

print("重复元素最多次数fen'bie为:")
for i in range(500):
    flag = 0
    for j in range(800):
        index = 800*i + j
        if(hash_map_tele[index] != 0):
            flag = 1
    if(flag == 0):
        print("tele_i:", i)
        break
for i in range(500):
    flag = 0
    for j in range(800):
        index = 800*i + j
        if(hash_map_name[index] != 0):
            flag = 1
    if(flag == 0):
        print("name_i:", i)
        break
tele_i: 39
name_i: 9

计算method1的ASL

c1 = 0  # 统计总的查找次数
for i in range(500):
    for j in range(800):
        index = 800*i + j
        if(hash_map_tele[index] != 0):
            c1 += (i+1)
print('method1-tele-asl:', c1/754)
c2 = 0  # 统计总的查找次数
for i in range(500):
    for j in range(800):
        index = 800*i + j
        if(hash_map_name[index] != 0):
            c2 += (i+1)
print('method1-name-asl:', c2/754)
method1-tele-asl: 12.10079575596817
method1-name-asl: 1.6498673740053051


计算method2的ASL

df1 = df.adr_电话_1.value_counts() 
print(df1)


514    39
916    33
329    32
47     31
767    31
187    29
216    29
473    28
619    27
646    26
384    26
62     26
9      25
372    25
175    21
530    20
6      20
852    19
256    18
130    18
780    17
690    17
343    16
917    16
653    15
537    15
685    13
423    12
513    11
891    11
201    10
771    10
311     9
859     7
994     7
93      6
386     5
568     5
938     5
206     4
28      4
688     3
890     3
788     2
119     2
590     1
309     1
752     1
494     1
894     1
434     1
Name: adr_电话_1, dtype: int64


df2 = df.adr_企业名称_1.value_counts() 
print(df2)
68      6
90      5
406     5
231     4
979     4
       ..
439     1
768     1
445     1
446     1
1006    1
Name: adr_企业名称_1, Length: 516, dtype: int64
print("有多少个元素在method2-tele基础表中,即只需查一次:",len(df1))
print("有多少个元素在method2-name基础表中,即只需查一次:",len(df2))


有多少个元素在method2-tele基础表中,即只需查一次: 51
有多少个元素在method2-name基础表中,即只需查一次: 516


# 基本表中的元素只需查一次,溢出区的元素和顺序表的查找次数是一样的,所以可以使用等差数列的计算公式进行计算,不过需要注意的就是溢出区的查找次数是从2开始的
print("method2-tele-asl:", (51 + (703*2 + (703*702)/2))/754)
print("method2-name-asl:", (516 + (238*2 + (238*237)/2))/754)


method2-tele-asl: 329.19098143236073
method2-name-asl: 38.720159151193634


最终得出结果


  • method1-tele-asl: 12.10079575596817
  • method1-name-asl: 1.6498673740053051
  • method2-tele-asl: 329.19098143236073
  • method2-name-asl: 38.720159151193634

分析


总的来说,重复元素的个数越多,哈希查找的效率就相应越低而法1的开放地址探测法对冲突的解决在本题中查找效率是明显优于公共溢出法的,但相应的占据了更大的存储空间至于平方去中法以及除留余数法在本题中映射出来的地址重复个数基本一致,故不相上下。



目录
相关文章
|
8月前
|
测试技术 开发者 Python
Python单元测试入门:3个核心断言方法,帮你快速定位代码bug
本文介绍Python单元测试基础,详解`unittest`框架中的三大核心断言方法:`assertEqual`验证值相等,`assertTrue`和`assertFalse`判断条件真假。通过实例演示其用法,帮助开发者自动化检测代码逻辑,提升测试效率与可靠性。
559 1
|
安全 测试技术 网络安全
如何在Python Web开发中进行安全测试?
如何在Python Web开发中进行安全测试?
681 158
|
安全 关系型数据库 测试技术
学习Python Web开发的安全测试需要具备哪些知识?
学习Python Web开发的安全测试需要具备哪些知识?
391 61
|
9月前
|
运维 Linux 开发者
Linux系统中使用Python的ping3库进行网络连通性测试
以上步骤展示了如何利用 Python 的 `ping3` 库来检测网络连通性,并且提供了基本错误处理方法以确保程序能够优雅地处理各种意外情形。通过简洁明快、易读易懂、实操性强等特点使得该方法非常适合开发者或系统管理员快速集成至自动化工具链之内进行日常运维任务之需求满足。
618 18
|
10月前
|
机器学习/深度学习 存储 算法
强化学习算法基准测试:6种算法在多智能体环境中的表现实测
本文系统研究了多智能体强化学习的算法性能与评估框架,选用井字棋和连珠四子作为基准环境,对比分析Q-learning、蒙特卡洛、Sarsa等表格方法在对抗场景中的表现。实验表明,表格方法在小规模状态空间(如井字棋)中可有效学习策略,但在大规模状态空间(如连珠四子)中因泛化能力不足而失效,揭示了向函数逼近技术演进的必要性。研究构建了标准化评估流程,明确了不同算法的适用边界,为理解强化学习的可扩展性问题提供了实证支持与理论参考。
493 0
强化学习算法基准测试:6种算法在多智能体环境中的表现实测
|
10月前
|
IDE 测试技术 API
python调试与测试
python调试与测试
|
9月前
|
安全 测试技术 API
Python 单元测试详解
单元测试是Python开发中不可或缺的环节,能确保代码按预期运行、发现Bug、提升代码质量并支持安全重构。本文从基础概念讲起,逐步介绍Python单元测试的实践方法,涵盖unittest框架、pytest框架、断言使用、Mock技巧及测试覆盖率分析,助你全面掌握单元测试技能。
493 0
|
算法 数据安全/隐私保护 计算机视觉
基于FPGA的图像双线性插值算法verilog实现,包括tb测试文件和MATLAB辅助验证
本项目展示了256×256图像通过双线性插值放大至512×512的效果,无水印展示。使用Matlab 2022a和Vivado 2019.2开发,提供完整代码及详细中文注释、操作视频。核心程序实现图像缩放,并在Matlab中验证效果。双线性插值算法通过FPGA高效实现图像缩放,确保质量。
|
10月前
|
人工智能 Java 测试技术
Java or Python?测试开发工程师如何选择合适的编程语言?
测试工程师如何选择编程语言?Java 还是 Python?多位资深专家分享建议:Python 入门简单、开发效率高,适合新手及自动化测试;Java 生态成熟,适合大型项目和平台开发。建议结合公司技术栈、个人基础及发展方向选择。长远来看,两者兼通更佳,同时关注 Go 等新兴语言。快速学习与实践才是关键。
|
11月前
|
测试技术 Python
Python测试报告生成:整合错误截图,重复用例执行策略,调整测试顺序及多断言机制。
如何组织这一切呢?你可以写一本名为“Python测试之道”的动作指南手册,或者创建一个包含测试策略、测试顺序、多断言机制的脚本库。只要你的测试剧本编写得足够独到,你的框架就会像一位执行任务的超级英雄,将任何潜伏于代码深处的错误无情地揪出来展现在光天化日之下。这些整理好的测试结果,不仅有利于团队协作,更像冒险故事中的精彩篇章,带给读者无尽的探索乐趣和深刻的思考。
283 10

热门文章

最新文章

推荐镜像

更多