転送:cnblog hanahimiハッシュ・テーブル・研究ノート
https://www.cnblogs.com/hanahimi/p/4765265.html
Pythonのデータ構造とアルゴリズム - ハッシュテーブル
研究ノートハッシュテーブル
リファレンスから翻訳:「複雑な思考」のオンライン版に対応する:のhttp://greenteapress.com/complexity/html/thinkcomplexity004.html
必要性の要素を除外することが、規則的に配列しながら、ハッシュテーブルを使用すると、非常に高速な検索と時間一定にすることができます
Pythonの組み込みデータ型:辞書、達成するためにハッシュテーブルを使用することです
ハッシュテーブルの動作原理を説明するために、我々は、辞書を使用せずに、ハッシュテーブル構造で実現してみてください。
私たちは、キー前記定義する必要があります - 以下の2つの動作を実現しながら、>値マップデータ構造を:
(K、V)を追加します:
キーからマップする新しい項目の追加 のk の値に Vを。
Python辞書とD、この操作が書かれている D [k]を= V。
(ターゲット)を得ます:
見上げると、キーに対応する値を返す ターゲットを。
Python辞書と D、この動作が書かれている D [標的] または d.get(ターゲット)。
単純な実装では、キーと値の間のタプルのマッピング関係を実装するために使用される線形テーブルを確立することです
class LinearMap(object):
""" 线性表结构 """
def __init__(self):
self.items = []
def add(self, k, v): # 往表中添加元素
self.items.append((k,v))
def get(self, k): # 线性方式查找元素
for key, val in self.items:
if key==k: # 键存在,返回值,否则抛出异常
return val
raise KeyError
我々が使用できるアドオンはご注文を維持するために項目のリストに要素を追加し、使用することができます取得、バイナリ検索モードをとり、時間計算量はO(n個のログ)です。ただし、リストに新しい要素を挿入することは、実際に線形操作であるので、このアプローチが最善の方法ではありません。同時に、我々はまだ、一定の時間要件を求めて到達しません。
私たちは、以下の改善を行うことができ、全体的なルックアップテーブルは、100のサブセグメントとして小さいリストのいくつかのセグメントに分割されます。追加またはサブセグメントを見つけるに与えるために、キーハッシュのハッシュ関数により得られた値、および計算。最初から検索リストに関しては、時間が大幅に短縮されます。が取得する拡張操作は、依然として線形であるが、BetterMapクラスが一歩近づくハッシュテーブルに私たちを行います
class BetterMap(object):
""" 利用LinearMap对象作为子表,建立更快的查询表 """
def __init__(self, n=100):
self.maps = [] # 总表格
for i in range(n): # 根据n的大小建立n个空的子表
self.maps.append(LinearMap())
def find_map(self, k): # 通过hash函数计算索引值
index = hash(k) % len(self.maps)
return self.maps[index] # 返回索引子表的引用
# 寻找合适的子表(linearMap对象),进行添加和查找
def add(self, k, v):
m = self.find_map(k)
m.add(k, v)
def get(self, k):
m = self.find_map(k)
return m.get(k)
テスト:
if __name__ == "__main__":
table = BetterMap()
pricedata = [("Hohner257", 257),
("SW1664", 280),
("SCX64", 1090),
("SCX48", 830),
("Super64", 2238),
("CX12", 1130),
("Hohner270", 620),
("F64C", 9720),
("S48", 1988)]
for item, price in pricedata:
table.add(k=item, v=price)
print
table.get("CX12")
# >>> 1130
print
table.get("QIMEI1248")
# >>> raise KeyError
各結合のハッシュ値が異なっていなければならないので、ハッシュ値のモジュロベースの値が異なるからです。
ときのn = 100、検索速度がLinearMap BetterMap 100倍程度です。
要素のサブセグメントは依然として線形検索であるように、明らかに、検索速度は、各LinearMapの長さが固定されていないが、前記制限されたBetterMapパラメータn、です。我々は、各サブセクションの最大長を制限することができる場合、この時間は一定の上限があり度の原因である単一のサブセグメントに見つけること、LinearMap.getの方法の時間計算量が一定となっています。LinearMapの要素数がしきい値を超えた場合、あなたは検索操作が一定の友人であることを保証することができ、このように多くのLinearMapを加えながらその結果、私たちは、要素の数を追跡するために全体のハッシュテーブル再配置を必要としています。
以下は、実現のハッシュテーブルです。
class HashMap(object):
def __init__(self):
# 初始化总表为,容量为2的表格(含两个子表)
self.maps = BetterMap(2)
self.num = 0 # 表中数据个数
def get(self, k):
return self.maps.get(k)
def add(self, k, v):
# 若当前元素数量达到临界值(子表总数)时,进行重排操作
# 对总表进行扩张,增加子表的个数为当前元素个数的两倍!
if self.num == len(self.maps.maps):
self.resize()
# 往重排过后的 self.map 添加新的元素
self.maps.add(k, v)
self.num += 1
def resize(self):
""" 重排操作,添加新表, 注意重排需要线性的时间 """
# 先建立一个新的表,子表数 = 2 * 元素个数
new_maps = BetterMap(self.num * 2)
for m in self.maps.maps: # 检索每个旧的子表
for k, v in m.items: # 将子表的元素复制到新子表
new_maps.add(k, v)
self.maps = new_maps # 令当前的表为新表
フォーカス部を追加し、関数は、それらが等しい場合、要素の数とサイズBetterMapをチェックし、「各LinearMapにおける要素の平均数が1である」、次いでサイズ変更メソッドを呼び出します。
新しいテーブルを作成、サイズ変更、サイズが2倍になる、そしてテーブルの古い要素が「再ハッシュをリハッシュ」新しいテーブルに、再び。
サイズを変更するプロセスは、我々はハッシュテーブルは、一定の時間を持って聞いているので、それは、非常にどのように良いように聞こえる、線形です。しかし、私たちは頻繁に再配置の操作を必要としないことに注意して、そのほとんどの時間に操作を追加、時折リニア一定です。追加操作N Nに比例する要素の合計時間ので、平均時間は定数を追加することです!
私たちは次のように、32個の要素を追加したいと仮定します。
1. 2の初期長さは、転位は、2倍の合計時間を最初の二つを追加する必要はない2
2. 4に並び替え第ADDは、2、3 3時間を消費します
3.第4回追加、6の合計のために、これまでに1を取りました
8に並び替え4.第五addは、4、5第五時間がかかりました
6 + 5 + 3 = 14の合計3これまでに6〜8回の合計消費5条
6. 9日追加、並び替え16、8、9 9回目を消費
前記第1の10〜16倍、これまで7の合計、14 + 9 + 7 = 30の合計時間を浪費
n個の要素を追加した後、32追加した後、単位時間当たりの合計時間は、上記の方法によって62は、nが2の累乗である場合、現在の総単位時間が2N-2であるため、平均時間を追加し、パターンを見つけることができます単位時間当たり2よりも絶対的に少ないです。
nが2の累乗である場合、nが大きくなると、最も適切な数は、平均時間がわずかに増加し、我々がOを達成することが重要である(1)。