Python中常见的数据结构可以统称为容器。序列(如列表和元组)、映射(如字典)以及集合(set)是三类主要的容器。线性数据结构分类:栈(stack)--先进后出、 队列(queue)-先进先出、双端队列(deque)、链表(LinkedList)。
常见的数据类型又分为:数字、字符串、元组、列表、字典、集合。
可变数据类型
列表、字典、集合 不可哈希
不可变数据类型元组、数字、字符串 可哈希
可哈希对象是对象拥有__hash__(self)内置函数的对象。对于可哈希的对象执行这个函数将会返回一个整数。
可哈希对象判断相等的唯一条件就是两者 的哈希值相等。下面通过一个例子来说明:
tuple_a = (1, 2, 3) # 元组a
dict_b = {"a": 1, "b": 2} # 字典b
dict_c = {"b": 2, "a": 1} # 字典c
print(tuple_a.__hash__)
print(dict_b.__hash__)
print(id(str(sorted(dict_b))))
print(id(str(sorted(dict_c))))
print(hash(str(sorted(dict_b))))
print(hash(str(sorted(dict_c))))
>>> <method-wrapper '__hash__' of tuple object at 0x00000275A3DF6C18>>>> None>>> 2704397351728
>>> 2704397351728
>>> -589638267386482414
>>> -589638267386482414我们可以输出结果中元组返回了一个对象的'__hash__'method,而字典返回的结果None;字典是不能hash的,
但是我们可以将字典转成字符串再进行hash,sorted是将字典进行排序,
返回的结果显示两者转成字符串后的id跟hash值都是一样的,间接的说明了字典b跟字典c也是相等的
(补充:sorted:适用于任何可迭代容器)
哈希有啥作用?
它是一个将大体量数据转化为很小数据的过程,甚至可以仅仅是一个数字,以便我们可以用在固定的时间复杂度下查询它,所以,哈希对高效的算法和数据结构很重要。Python 中基于hash的2个数据类型是dict and set , 之前说dict查询速度快,为何快? 说set天生去重,怎么做到的?其实都是利用了hash的特性,我们下面来剖析dict 为何查询速度超快,且不受dict大小影响 ?
解析:假设我要存14亿人的基本信息
data = {
"张三":[23742364782642342323234,28,"山东济南"],
"李四":[12124234232311214458271,25,"北京昌平"],
"王五":[23030293483727384383929,33,"山东济南"],
"赵六":[42302033030302482634674,28,"河北保定"],
... ...
}
dict 的每个key 都要先经过hash生成一段固定长度的hash值,假设生成的hash值如下dict会把这些数字按大小排序好放在一个列表里kd = [53, 67, 81, 99]
当我们想查找"赵六"的信息时, 会把“赵六”先hash, 得到99这个值,然后拿这个值去到kd列表里找,想象这个列表有14亿个值 ,如何快速找到99? 二分法就行 ,只要找到了99的位置,就可以定位到赵六对应的value的值了。 通过2分法查找,每次数据量都会少一半,这样查找最多31次(2**31=2147483648)就能从20亿信息里找到这个人的信息。当然 dict 真实的查找算法比这个还要复杂些, 我只是通过这个例子让大家理解下为何基于hash的数据类型查找速度会快很多。
set去重是因为每存一个值到set里时, 都要先经过hash,然后通过得出的这个hash值算出应该存在set里的哪个位置,存的时候会先检查那个位置上有没有值 ,有的话就对比是否相等,如果相等,则不再存储此值。 如果不相等(即为空),则把新值存在这。