为什么python中的hash函数需要固定的时间来操作可变长度的字符串?

问题描述

包括对可变长度字符串的hash()操作在内的程序的运行时间开始,我觉得hash()函数可能需要花费恒定的时间才能对不同长度的字符串进行操作。为了验证我的假设,我制定了以下策略-

  • 创建长度为k的字符串
  • 哈希字符串并记录hash()操作时间t
  • 对于从0到100,00的k重复此操作,并生成字符串长度k与时间t的图。

因此,如果我猜想hash()函数在对字符串进行操作时是恒定时间操作是正确的,那么您能不能用外行术语解释为什么会这样?关于概念或理论上的解释,而不是参考源代码,这将是更可取的,因为即使大字符串如何即时产生散列,而对字符长度无所谓。

以下是上述策略的代码实现-

import random
import time
import pylab

def form_str(k,n):
    """
        Form k-length strings of arbitrary characters,n in number.
    """
    for i in range(n):
        random_str = ''
        for j in range(k):
            nextchar = random.choice('ABCDEFGHIJKLMnopQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')
            random_str += nextchar
        yield random_str

def time_hash(k,n):
    """
        Find the total time to hash n strings of k length each.
    """
    
    total_time = 0.0
    for element in form_str(k,n):
        start_time = time.time()
        # Because hash() works almost instantaneously we repeat
        # it 100,000 times to get a non-zero run time.
        for i in range(100000):
            hash(element)
        end_time = time.time()
        total_time += (end_time - start_time)
    return round(total_time,2)

# print(time_hash(100,100))  

def plot_time():
    """
        Plots the time vs string length (k) over a range of k-values.
    """
    x_values,y_values = [],[]
    for k in range(0,100000,5000):
        x_values.append(k)
        y_values.append(time_hash(k,100))
    # print(y_values)
    pylab.figure(1)
    pylab.title('Hash_Time_Complexity')
    pylab.xlabel('Length of string')
    pylab.ylabel('Time taken to hash string (100 x 100000 times)')
    pylab.plot(x_values,y_values,'r:',label = 'Hash time')
    pylab.show()

plot_time()
# From the plot it is clear that indifferent of the string length
# hashing takes the same time.

以下是生成的图-

enter image description here

解决方法

由于字符串是不可变的,因此字符串的哈希码仅计算一次,然后缓存。

更好的基准测试方法是生成长度为k的不同(唯一)字符串并平均其哈希时间,而不是多次调用同一字符串的哈希。