每当我们试图通过我们的数据实现某种搜索逻辑时,我们希望它是 高效.在小程序中可能不是这样,但对于拥有庞大代码库的大型应用程序,运行任何一种逻辑的搜索、删除或修改时间都应该是最小的。
Python中的字典是用来存储数据的,即Key:值对。它们使用一种叫做Hashing的技术来执行基于时间的搜索操作,这几乎与字典的大小无关**。**
什么是Hashing?
散列是一种用来对任何类型的数据进行排序和索引的技术。散列允许我们对大量的数据或输入进行索引,并将它们存储在较小的输出空间中,所使用的键一般是用一种叫做散列函数的东西来创建的,它本质上是某种应用于我们的输入数据的数学逻辑,从而得到一个数值。
哈希的概念
让我们假设我们有三个字符串,我们想用某种数学逻辑以一种有效的方式来存储它们。这里我们有约翰、彼得和卡莉三个字符串。因此,如果你想用散列法来存储它们,这里的第一步是我们用一些散列函数将这些字符串变成一个数字。
如果我们使用散列函数将这些字符串转换为数字,我们首先将约翰字转换为10,然后我们将彼得转换。它被转换为5。然后我们在继续转换Carrie,这将是11。因此,我们已经将我们的字符串转换成了数字。
现在你可能会感兴趣,如何转换,这里的 Hash函数是什么,它是如何工作的。我们将在文章中进一步了解这个问题。
Python中的哈希函数
哈希函数负责通过使用一些公式将这些字符串转换为数字。
接下来,我们必须将这些数字存储在一些数据结构中。如果我们有一个数组或python列表,其中有12个单元,如图所示,通过使用这个哈希函数生成的数字,我们将把这些字符串插入这些数组中。
所以对于第一个字符串,也就是约翰,我们有10个。我们将John 字符串插入到 10的索引在这个数组中。然后,下一个字符串是彼得。所以当我们把它转换成数字时,它就变成了5。
我们将插入Peter字符串到 5的索引.现在,下一个词是Carrie。当我们通过使用这里的哈希函数转换Carrie时,它就变成了11。所以我们将把Carrie插入到 11的索引到这边的这个数组中。我们已经完成了这些字符串到整数的转换,我们正在将这些字符串插入这个数组中。
使用哈希函数读取或访问数据
现在,问题是,如果我们想从这里的数组中读取数据,我们如何访问它?
同样,逻辑也是一样的。例如,如果我们想访问约翰,我们要做的第一件事就是使用同样的哈希函数,将约翰转换成数字。每次我们转换相同的字符串时,结果都是一样的。所以我们会得到10。基于10的索引,我们可以访问这边的这个元素。
为什么我们需要Hashing?
我们知道,根据索引访问数组或 Python 列表中的一个元素需要 ***O(1)***时间复杂度.这就是为什么在数据结构中搜索一个给定的值时,散列是非常重要的。通过这样做,我们可以很容易地确定这个字符串是否在这个数组中。
假设我们想开发一个应用程序,其中大量使用搜索操作,我们希望我们的应用程序尽可能快地执行。在这种情况下,我们可以使用散列。在搜索操作方面,散列也比其他数据结构表现得更好。
散列术语
- 哈希函数:它是一种逻辑或数学公式,可用于将任意大小的输入数据映射到固定或较小大小的输出。
- 哈希值:它是由哈希函数返回的值。
- 哈希表:它是实现关联数组抽象数据类型的数据结构,也是可以将键映射到值的结构。
- 碰撞:当一个哈希函数的两个不同的键产生相同的输出时,就会发生碰撞。
在 Python 中实现 HashMap
让我们试着通过实现一个哈希图来了解它的概况。我们将创建一个包含基本函数的自定义类。下面是包含在我们的自定义类中的函数。代码本身包含了我们之前在文章中讨论的所有解释。
- _hash(self,key)这是我们定义的哈希函数或数学逻辑,我们将其应用于密钥,将其转换为一个积分值。
- set*(self,key,value)这个函数将允许我们向我们的哈希图添加一个键|值对。
- get(self,key):要为给定的键检索一个值,可以利用这个函数。
- __str__(self)将完整的哈希图输出到我们的终端。
代码
class HashMap(object):
def __init__(self, size):
"""Initializing the list with the argument size for our HashMap"""
self.data = [[]] * (size)
def _hash(self, key):
"""Hash Function:
marked as a private method in the Object"""
# Initialize
hash_value = 0
# Iterating and generating hashed values using the logic below
# Logic: Taking the initial value of 0 and adding to it the ASCII encoding for each character,
# and multiplying by the index value. After that we are taking the modulus of the result using the
# length of the array
# This becomes our hashed value i.e. the index position of the input to be placed
# in the output space
for i in range(len(key)):
hash_value = (hash_value + ord(key[i]) * i) % len(self.data)
return hash_value
def set(self, key, value):
# Represents the index position where we want to store our data
address = self._hash(key)
if not self.data[address]:
self.data[address] = []
# If there is a collision of index value i.e. our hashed value
# then simply add on to that array
self.data[address].append([key, value])
return self.data
def get(self, key):
# Getting the hashed value again, with the same hash function to locate the value
# for the given key
address = self._hash(key)
# assigning the entire array to a variable in-order to operate later
currentBucket = self.data[address]
if currentBucket:
# Iterating over the entire list to get the value
for i in range(len(currentBucket)):
# Check to retrieve the value
if currentBucket[i][0] == key:
# If found, return the current bucket
return currentBucket[i][1]
# If no value present
return "Data Not Found"
# In order to print the hashmap to see the structure
def __str__(self):
return "".join(str(item) for item in self.data)
# Instantiating from our Object Class with 50 buckets
myHash = HashMap(50)
# Setting the values to the hash table
myHash.set("john", 123)
myHash.set("peter", 567)
myHash.set("carrie", 898)
# Printing the entire hash table
print(myHash)
# Getting the values from the hash table using the keys
print(myHash.get("john")) # Output: 123
print(myHash.get("guava")) # Output: Data Not Found
总结
在这篇文章中,我们介绍了使用Python创建哈希图的关键术语和方法。顾名思义,它就像使用数据创建一个地图,在底层逻辑上提供一个抽象的表示。它们提供了一种有效的方式来显示和定位基于键的值,也可以根据键来插入和删除值。