python里的字典就像java里的HashMap,以键值对的方式存在并操作,其特点如下
1.和邻接表的结构一样,一个定长的数组,这个数组的每一个元素都是一个链表的头结点,headers是一个定长的数组,数组当中的每一个元素都是一个链表的头结点。也就是说根据这个头结点,我们可以遍历这个链表。数组是定长的,但是链表是变长的,所以如果我们发生元素的增删改查,本质上都是通过链表来实现的,总之:它本质上就是一个元素是链表的数组。
2.HashMap中每个节点的存储方式为
3.当hash值不同时,对象一定不同。当hash值相同时,对象可能相同,也可能不同
4.可能大体上看了,具体数据结构里面是可以把哈希表看成一个二维数组,哈希表中的每一个元素又存储了哈希值(hash)、键(key)、值(value)3个元素。
enteies = [
['--', '--', '--'],
[hash, key, value],
['--', '--', '--'],
['--', '--', '--'],
[hash, key, value],
]
由上可见哈希表的存储结构,我们也可以看出,元素之间有一些空元素,我们通过增加一个元素来讲解具体实现。
# 加入输入是一个s=jhkdfhii,统计次数
from collections import defaultdict
Defdict = defaultdict(int)
for i in range(len(list(s))):
Defdict[s[i]] += 1 # 对于value的自加,也可以赋值(比如value是下标i)
records = dict() # 初始化
# 这里用的dict()注意dict里面是空要先判断在不在里面赋值为1,defaultdict不用判断可以直接+1
for j in range(len(list(s))):
if s[j] not in records # 判断是否含有元素
record[s[j]] = idx #一样的可以赋值或者自加
return record # 返回字典的key,value
defaultdict和dict和Counter区别
- 当定义一个字典没有相应的key值时,defauldict()会在字典中添加这个key值并赋值为0(当字典里的key不存在但被查找时,返回的不是keyError而是一个默认值,)
- 而直接使用dict()来定义则会报错:找不到相应的key值(当字典里的key不存在但被查找时,返回的是keyError)
- 但使用if语句来主动为key赋值,也能达到defaultdict()一样的效果。
- Counter和defaultdict比较, Counter 的问题就是其数值必须是整数,本身就是用于统计数量,因此如果我们需要的数值是字符串,列表或者元组,那么就不能继续用它。
# * 传入的是列表s
s = [('color', 'blue'), ('color', 'orange'), ('color', 'yellow'), ('fruit', 'banana'), ('fruit', 'orange'),
('fruit', 'banana')]
d = defaultdict(list)
for k, v in s:
d[k].append(v)
print(d)
# 输出结果:defaultdict(, {'color': ['blue', 'orange', 'yellow'], 'fruit': ['banana', 'orange', 'banana']})
# * 传入的是集合set
s = [('color', 'blue'), ('color', 'orange'), ('color', 'yellow'), ('fruit', 'banana'), ('fruit', 'orange'),
('fruit', 'banana')]
d = defaultdict(set)
for k, v in s:
d[k].add(v)
print(d)
# 输出结果:defaultdict(, {'color': {'blue', 'yellow', 'orange'}, 'fruit': {'banana', 'orange'}})
# 这里需要注意的就是列表和集合的添加元素方法不相同,列表是list.append(),而集合是set.add()。
# 对于 Counter ,还可以通过关键字来初始化:
c = Counter(cats=4, dogs=8)
print(c)
# 输出:
Counter({'dogs': 8, 'cats': 4})
# Counter 的一些方法,除了上述介绍的most_common()外,还有:
# elements():返回一个迭代器,将所有出现元素按照其次数来重复 n 个,并且返回任意顺序,但如果该元素统计的次数少于 1 ,则会忽略,例子如下:
c = Counter(a=4, b=2, c=0, d=-2)
sorted(c.elements())
# ['a', 'a', 'a', 'a', 'b', 'b']
# subtract():减法操作,输入输出可以是 0 或者负数
c = Counter(a=4, b=2, c=0, d=-2)
d = Counter(a=1, b=2, c=3, d=4)
c.subtract(d)
print(c)
# Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})
# 此外,还有以下这些方法:
# 求和
sum(c.values())
# 清空 Counter
c.clear()
# 转换为 列表
list(c)
# 转换为 集合
set(c)
# 转换为 字典
dict(c)
# 键值对
c.items()
Counter(dict(list_of_pairs))
# 输出 n 个最少次数的元素
c.most_common()[:-n-1:-1]
# 返回非零正数
+c
# 返回负数
-c
# 此外,也可以采用运算符+,-,&,|,各有各不同的实现作用:
c = Counter(a=3, b=1)
d = Counter(a=1, b=2)
# 加法操作 c[x] + d[x]
print(c + d) # Counter({'a': 4, 'b': 3})
# 减法,仅保留正数
print(c - d ) # Counter({'a': 2})
# 交集: min(c[x], d[x])
print(c & d) # Counter({'a': 1, 'b': 1})
# 并集: max(c[x], d[x])
print(c | d) # Counter({'a': 3, 'b': 2})
# 例如统计下面一句话的单词个数
text = "I need to count the number of word occurrences in a piece of text. How could I do that? " \
"Python provides us with multiple ways to do the same thing. But only one way I find beautiful."
# 方法一:defaultdict
from collections import defaultdict
word_count_dict = defaultdict(int)
for w in text.split(" "):
word_count_dict[w] += 1
# 方法二:Counter(或者直接 word_counter = Counter(text.split(" ")))
from collections import Counter
word_count_dict = Counter()
for w in text.split(" "):
word_count_dict[w] += 1
print('most common word: ', word_count_dict.most_common(10))
# 补充Counter:Counter 其实就是一个计数器,它本身就应用于统计给定的变量对象的次数,因此,我们还可以获取出现次数最多的单词:
# Counter其他的一些应用例子:
# Count Characters
print(Counter('abccccccddddd'))
# Count List elements
print(Counter([1, 2, 3, 4, 5, 1, 2]))
# 输出结果:
Counter({'c': 6, 'd': 5, 'a': 1, 'b': 1})
Counter({1: 2, 2: 2, 3: 1, 4: 1, 5: 1})
# 方法三:{}
word_count_dict = {}
for w in text.split(" "):
if w in word_count_dict:
word_count_dict[w] += 1
else:
word_count_dict[w] = 1
# 1.获得字典dict中value的最小值所对应的键的方法
Min = min(num_dict, key=num_dict.get)
# 2.翻转为,这个可以根据value查找key
my_dic = {k:v for v,k in Defdict.items()} # 第一种
my_dic = dict(zip(Defdict.values(),Defdict.keys())) # 第二种
# 第三种
my_dic = {}
for k,v in Defdict.items():
my_dic[v] = k
# 3.根据值查找键
# 遍历
my_dict ={"John":1, "Michael":2, "Shawn":3}
def get_key(val):
for key, value in my_dict.items():
if val == value:
return key
return "There is no such Key"
print(get_key(1))
print(get_key(2))
# 如果是查找值最小的键呢,先由1得到Min
print(get_key(Min))
# 3.根据值查找键
my_dict ={"John":3, "Michael":3, "Shawn":2}
list_of_key = list(my_dict.keys()) # 查找所有的键
list_of_value = list(my_dict.values()) # 查找所有的值
position = list_of_value.index(3) # value=3的
the_Key = list_of_key[position] # 输出的是value=3对应的第一个John
# 注意!!!防止值映射为下标
position2 = list_of_value[1] # 在[3,3,2]取出下标1,也就是第二个value=3,
the_Key = list_of_key[position2] # 输出的是key对应的['John','Michael','Shawn']下标为3的,没有就会报错
# 4.根据键查询值
dictt = {'name': 'Tom', 'age': 18, 'love': 'python'}
the_value = dictt ['key'] # 4.1直接使用键查找
# 4.2或者利用get函数使用键查找值
the_value = dictt .get('age') # 如果key不存在返回None
the_value = dictt .get('age','默认值') # 如果键不存在,设置返回默认值
# 4.3setdefault和get函数差不多,但是如果键不存在,则查找的内容当做键放入字典,并设置默认值,不设置为None
the_value = dictt.setdefault('age2')
# 5.查询所有键和值和键值对
the_keys = dictt.keys()
the_values = dictt.values()
the_items = dictt.items()
# 注意:返回的数据结构有三种不同的数据类型:dict_keys(),dict_values(),dict_items(),这样的数据是没有办法按照列表下标(例如the_values[1])进行访问的。
# 可以先转换列表
the_values = list(the_values)
# 6.has_key()判断给定的键是否存在于字典中,返回True 或者 False
dict = {'Name': 'Maxsu', 'Age': 7}
print ("Value : %s" % dict.has_key('Age')) # Value:True
参考自:https://blog.csdn.net/chinesehuazhou2/article/details/108786521
要用这个hash值来决定这个节点应该存放在哪一条链表当中。只要hash函数确定了,只要值不变,计算得到的hash值也不会变。所以我们查询的时候也可以遵循这个逻辑,找到key对应的hash值以及对应的链表。
在Python当中由于系统提供了hash函数,所以整个过程变得更加方便。我们只需要两行代码就可以找到key对应的链表。
hash_key = hash(key) % len(self.headers)
linked_list = self.headers[hash_key]
明白了hash函数的作用了之后,hashmap的问题就算是解决了大半。因为剩下的就是一个在链表当中增删改查的问题了,比如我们要通过key查找value的时候。
当我们通过hash函数确定了是哪一个链表之后,剩下的就是遍历这个链表找到这个值。这个函数我们可以实现在LinkedList这个类当中,非常简单,就是一个简单的遍历。
链表的节点查询逻辑有了之后,hashmap的查询逻辑也就有了。因为本质上只做了两件事,一件事根据hash函数的值找到对应的链表,第二件事就是遍历这个链表,找到这个节点。
因为put方法逻辑和get相反。我们把查找换成添加或者是修改即可。
python库函数实现hashMap
自定义的完整代码:
import random
class Node:
def __init__(self, key, val, prev=None, succ=None):
self.key = key
self.val = val
# 前驱
self.prev = prev
# 后继
self.succ = succ
def __repr__(self):
return str(self.val)
class LinkedList:
def __init__(self):
self.head = Node(None, 'header')
self.tail = Node(None, 'tail')
self.head.succ = self.tail
self.tail.prev = self.head
self.size = 0
def append(self, node):
# 将node节点添加在链表尾部
prev = self.tail.prev
node.prev = prev
node.succ = prev.succ
prev.succ = node
node.succ.prev = node
self.size += 1
def delete(self, node):
# 删除节点
prev = node.prev
succ = node.succ
succ.prev, prev.succ = prev, succ
self.size -= 1
def get_list(self):
# 返回一个包含所有节点的list,方便上游遍历
ret = []
cur = self.head.succ
while cur != self.tail:
ret.append(cur)
cur = cur.succ
return ret
def get_by_key(self, key):
cur = self.head.succ
while cur != self.tail:
if cur.key == key:
return cur
cur = cur.succ
return None
class HashMap:
def __init__(self, capacity=16, load_factor=5):
self.capacity = capacity
self.load_factor = load_factor
self.headers = [LinkedList() for _ in range(capacity)]
def get_hash_key(self, key):
return hash(key) & (self.capacity - 1)
def put(self, key, val):
hash_key = self.get_hash_key(key)
linked_list = self.headers[hash_key]
if linked_list.size >= self.load_factor * self.capacity:
self.reset()
hash_key = self.get_hash_key(key)
linked_list = self.headers[hash_key]
node = linked_list.get_by_key(key)
if node is not None:
node.val = val
else:
node = Node(key, val)
linked_list.append(node)
def get(self, key):
hash_key = self.get_hash_key(key)
linked_list = self.headers[hash_key]
node = linked_list.get_by_key(key)
return node.val if node is not None else None
def delete(self, key):
node = self.get(key)
if node is None:
return False
hash_key = self.get_hash_key(key)
linked_list = self.headers[hash_key]
linked_list.delete(node)
return True
def reset(self):
headers = [LinkedList() for _ in range(self.capacity * 2)]
cap = self.capacity
self.capacity = self.capacity * 2
for i in range(cap):
linked_list = self.headers[i]
nodes = linked_list.get_list()
for u in nodes:
hash_key = self.get_hash_key(u.key)
head = headers[hash_key]
head.append(u)
self.headers = headers
更通俗的例子
table = {'abc':1, 'def':2, 'ghi':3}
print table
#字典反转
map=dict([(v,k) for k, v in table.iteritems()])
#字典遍历
for key in map.keys():
print key,":",map[key]
print len(map)
print map.keys()
print map.values()
#字典的增,删,改,查
#在这里需要来一句,对于字典的扩充,只需定义一个新的键值对即可,
#而对于列表,就只能用append方法或分片赋值。
map[4]="xyz"
print map
del map[4]
print map
map[3]="update"
print map
if map.has_key(1):
print "1 key in"