数据结构作业
Problem 03: Linked HashTable
一、哈希表
- 功能:请实现一个链式的哈希表
具体如下:
- 1.如果您有一个带有填充因子“0.5”和“100”个桶的哈希表,那么一旦它存储key-value元素对数超过“0.5 * 100 = 50”个元素,就需要使捅数量扩充到“200”个 即需要实现函数:
_resize()
, 处理扩容需要完成的方法: - 2.
is_empty(self)
- 判断self是否为空HashTable。 - 3.
__getitem__(self, key)
- 返回self[key]
。如果哈希表中不存在`key`,返回defaultvalue。如果哈希表中不存在`key`并且defaultvalue
是None
,需要引发`KeyError`。以及get(self, key, defualtvalue=None)
- 4.
__setitem__(self, key, value)
- 如果key存在,将self[key]
设置为 value,否则加入一个新的键值对。 - 5.
find_bucket(self, key)
- 返回self[key]
存储在哈希表的桶号。 - 6.
remove(self, key, defaultvalue=None)
- 删除self[key]
,并返回对应的值。如果哈希表中不存在`key`,则返回defaultvalue
。如果哈希表中不存在`key`并且defaultvalue
是None
,需要引发`KeyError`。 - 7.
__iter__(self)
- 返回哈希表中键的迭代器。 - 8.
values(self)
- 应该是一个生成器,返回self中value的迭代器。 - 9.
items(self)
- 应该是一个生成器,将哈希表的数据项作为元组 (key,value),返回self中数据项的迭代器。
- 提供了部分可供使用的接口:(鼓励自行实现接口)
1.提供了
Node
类:
包含了
self.data()
方法,获取内容
self.next
,获得下一个结点
self.prior
,获得前一个结点
——此对象支持print打印
2.LinkedList
类:
self.add(val)
向链表中添加元素,例如linkedlist.add( (k, v) )
self.remove(val)
移除链表中的元素linkedlist.remove(k)
会删除以k为键的一个元素
self.is_empty()
判断链表是否为空
self.size()
统计此链表的元素数目
self.get_head().next
获得第一个元素
——此对象支持print打印
- 代码部分
class Node:
def __init__(self, node_data):
self._data = node_data
self._next = None
def get_data(self):
return self._data
def set_data(self, node_data):
self._data = node_data
def get_next(self):
return self._next
def set_next(self, node_next):
self._next = node_next
next = property(get_next, set_next)
def __str__(self):
return str(self._data)
class MyLinkedList:
def __init__(self):
self.head = None
def is_empty(self):
return self.head is None
def add(self, item):
temp = Node(item)
temp.set_next(self.head)
self.head = temp
def size(self):
current = self.head
count = 0
while current is not None:
count = count + 1
current = current.get_next()
return count
def search(self, item):
current = self.head
count = 0
while current is not None:
count += 1
if current.get_data() == item:
return [True,count]
current = current.get_next()
return [False,None]
def removenode(self, item):
current = self.head
previous = None
while current is not None:
if current.get_data() == item:
break
previous = current
current = current.get_next()
if current is None:
raise ValueError("{} is not in the list".format(item))
if previous is None:
self.head = current.get_next()
else:
previous.set_next(current.get_next())
class ExtensibleHashTable:
def __init__(self,capacity=16,factor=0.125):
self.capacity = capacity
self.size = 0
self.slots = [None]*capacity
self.value_s = [None]*capacity
self.factor = factor
def _hash_function(self, key):
return (id(key) // 10) % self.capacity
def _resize(self):
self.size = 0
old_slots, old_values = self.slots, self.value_s
self.capacity *= 2
self.slots = [None] * self.capacity
self.value_s = [None] * self.capacity
for i in range(len(old_slots)):
if old_slots[i] is None:
continue
current = old_slots[i].head
current_value = old_values[i].head
while current is not None:
self.__setitem__(current.get_data(), current_value.get_data())
current = current.get_next()
current_value = current_value.get_next()
def __setitem__(self, key, value):
hash_value = self._hash_function(key)
if self.slots[hash_value] is None:
self.slots[hash_value] = MyLinkedList()
self.slots[hash_value].add(key)
self.value_s[hash_value] = MyLinkedList()
self.value_s[hash_value].add(value)
self.size += 1
factor = self.size / self.capacity
if factor >= self.factor:
self._resize()
else:
if self.slots[hash_value].search(key)[0] is True:
current = self.value_s[hash_value].head
count = 0
while current is not None:
count += 1
if count == self.slots[hash_value].search(key)[1]:
current.set_data(value)
break
current = current.get_next()
else:
self.slots[hash_value].add(key)
self.value_s[hash_value].add(value)
def __getitem__(self, key,defautvalue = None):
start_slot = self._hash_function(key)
if self.slots[start_slot] is None:
return "KeyError"
elif self.slots[start_slot].search(key)[0] is True:
current = self.value_s[start_slot].head
count = 0
while current is not None:
count += 1
if count == self.slots[start_slot].search(key)[1]:
return current.get_data()
current = current.get_next()
else:
return defautvalue
def is_empty(self):
return self.size == 0
def remove(self,key,defautvalue = None):
remove_slot = self._hash_function(key)
if self.slots[remove_slot] is None:
return "KeyError"
elif self.slots[remove_slot] is not None and self.slots[remove_slot].search(key)[0] is True:
current = self.slots[remove_slot].head
current_value = self.value_s[remove_slot].head
previous = None
previous_value = None
while True:
remove_value = current_value.get_data()
if current.get_data() == key:
break
previous = current
previous_value = current_value
current = current.get_next()
current_value = current_value.get_next()
if previous is None:
self.slots[remove_slot].head = current.get_next()
self.value_s[remove_slot].head = current_value.get_next()
self.size -= 1
return remove_value
else:
previous.set_next(current.get_next())
previous_value.set_next(current_value.get_next())
self.size -= 1
return remove_value
else:
return defautvalue
def get(self,key,value = None):
for bucket in range(self.capacity):
if self.slots[bucket] is not None and self.slots[bucket].search(key)[0] is True:
return bucket
else:
return value
def __iter__(self):
for key in self.slots:
if key is not None:
current = key.head
while current is not None:
yield(current.get_data())
current = current.get_next()
def values(self):
lst = []
for value in self.value_s:
if value is not None:
current = value.head
while current is not None:
lst.append(current.get_data())
current = current.get_next()
return lst
def items(self):
lst = []
for item in self.slots:
if item is not None:
current = item.head
while current is not None:
tup = []
tup.append(current.get_data())
tup.append(self.__getitem__(current.get_data()))
tup = tuple(tup)
lst.append(tup)
current = current.get_next()
return lst
def keys(self):
return self.__iter__()
- 演示结果