logo

分離チェーンを使用した Python でのハッシュ テーブルの実装

ハッシュ表 データの素早い挿入、削除、取得を可能にするデータ構造です。これは、ハッシュ関数を使用してキーを配列内のインデックスにマップすることで機能します。この記事では、衝突を処理するために別個のチェーンを使用して Python でハッシュ テーブルを実装します。

ハッシュのコンポーネント

ハッシュの構成要素



個別のチェーンは、ハッシュ テーブル内の衝突を処理するために使用される手法です。 2 つ以上のキーが配列内の同じインデックスにマップされる場合、それらはそのインデックスのリンク リストに格納されます。これにより、複数の値を同じインデックスに保存し、キーを使用してそれらの値を取得できるようになります。

セパレートチェーンを使用したハッシュテーブルの実装方法

個別のチェーンを使用してハッシュ テーブルを実装する方法:



2 つのクラスを作成します。 ノード ' そして ' ハッシュ表 '。

ノード ' クラスはリンクされたリスト内のノードを表します。各ノードには、キーと値のペアに加えて、リスト内の次のノードへのポインターが含まれます。

Python3






class> Node:> >def> __init__(>self>, key, value):> >self>.key>=> key> >self>.value>=> value> >self>.>next> => None>

>

>

「HashTable」クラスには、リンクされたリストを保持する配列と、ハッシュ テーブルからデータを挿入、取得、削除するメソッドが含まれます。

Python3




class> HashTable:> >def> __init__(>self>, capacity):> >self>.capacity>=> capacity> >self>.size>=> 0> >self>.table>=> [>None>]>*> capacity>

>

>

__熱い__ ' メソッドは、指定された容量でハッシュ テーブルを初期化します。 「」を設定します 容量 ' そして ' サイズ ' 変数を使用し、配列を「なし」に初期化します。

次の方法は「 _ハッシュ ' 方法。このメソッドはキーを受け取り、キーと値のペアを格納する配列内のインデックスを返します。 Python の組み込みハッシュ関数を使用してキーをハッシュし、モジュロ演算子を使用して配列内のインデックスを取得します。

Python3




def> _hash(>self>, key):> >return> hash>(key)>%> self>.capacity>

>

>

'入れる' メソッドは、キーと値のペアをハッシュ テーブルに挿入します。 ‘を使用してペアを保存するインデックスを取得します。 _ハッシュ ' 方法。そのインデックスにリンクされたリストがない場合は、キーと値のペアを持つ新しいノードを作成し、それをリストの先頭に設定します。そのインデックスにリンクされたリストがある場合は、最後のノードが見つかるかキーがすでに存在するまでリストを繰り返し、キーがすでに存在する場合は値を更新します。キーが見つかった場合は、値を更新します。キーが見つからない場合は、新しいノードを作成し、リストの先頭に追加します。

Python3




def> insert(>self>, key, value):> >index>=> self>._hash(key)> >if> self>.table[index]>is> None>:> >self>.table[index]>=> Node(key, value)> >self>.size>+>=> 1> >else>:> >current>=> self>.table[index]> >while> current:> >if> current.key>=>=> key:> >current.value>=> value> >return> >current>=> current.>next> >new_node>=> Node(key, value)> >new_node.>next> => self>.table[index]> >self>.table[index]>=> new_node> >self>.size>+>=> 1>

>

>

検索 メソッドは、指定されたキーに関連付けられた値を取得します。まず、キーと値のペアを保存するインデックスを取得します。 _ハッシュ 方法。次に、そのインデックスにあるリンク リストでキーを検索します。キーが見つかった場合は、関連付けられた値を返します。キーが見つからない場合は、 キーエラー

Python3




def> search(>self>, key):> >index>=> self>._hash(key)> >current>=> self>.table[index]> >while> current:> >if> current.key>=>=> key:> >return> current.value> >current>=> current.>next> >raise> KeyError(key)>

>

>

'取り除く' メソッドは、ハッシュ テーブルからキーと値のペアを削除します。まず、` を使用してペアを保存するインデックスを取得します。 _ハッシュ `メソッド。次に、そのインデックスにあるリンク リストでキーを検索します。キーが見つかった場合は、リストからノードを削除します。キーが見つからない場合は、「`」が発生します。 キーエラー `。

Python3




def> remove(>self>, key):> >index>=> self>._hash(key)> > >previous>=> None> >current>=> self>.table[index]> > >while> current:> >if> current.key>=>=> key:> >if> previous:> >previous.>next> => current.>next> >else>:> >self>.table[index]>=> current.>next> >self>.size>->=> 1> >return> >previous>=> current> >current>=> current.>next> > >raise> KeyError(key)>

>

>

「__str__」 ハッシュ テーブルの文字列表現を返すメソッド。

Python3


部分文字列文字列java



def> __str__(>self>):> >elements>=> []> >for> i>in> range>(>self>.capacity):> >current>=> self>.table[i]> >while> current:> >elements.append((current.key, current.value))> >current>=> current.>next> >return> str>(elements)>

>

>

「HashTable」クラスの完全な実装は次のとおりです。

Python3




class> Node:> >def> __init__(>self>, key, value):> >self>.key>=> key> >self>.value>=> value> >self>.>next> => None> > > class> HashTable:> >def> __init__(>self>, capacity):> >self>.capacity>=> capacity> >self>.size>=> 0> >self>.table>=> [>None>]>*> capacity> > >def> _hash(>self>, key):> >return> hash>(key)>%> self>.capacity> > >def> insert(>self>, key, value):> >index>=> self>._hash(key)> > >if> self>.table[index]>is> None>:> >self>.table[index]>=> Node(key, value)> >self>.size>+>=> 1> >else>:> >current>=> self>.table[index]> >while> current:> >if> current.key>=>=> key:> >current.value>=> value> >return> >current>=> current.>next> >new_node>=> Node(key, value)> >new_node.>next> => self>.table[index]> >self>.table[index]>=> new_node> >self>.size>+>=> 1> > >def> search(>self>, key):> >index>=> self>._hash(key)> > >current>=> self>.table[index]> >while> current:> >if> current.key>=>=> key:> >return> current.value> >current>=> current.>next> > >raise> KeyError(key)> > >def> remove(>self>, key):> >index>=> self>._hash(key)> > >previous>=> None> >current>=> self>.table[index]> > >while> current:> >if> current.key>=>=> key:> >if> previous:> >previous.>next> => current.>next> >else>:> >self>.table[index]>=> current.>next> >self>.size>->=> 1> >return> >previous>=> current> >current>=> current.>next> > >raise> KeyError(key)> > >def> __len__(>self>):> >return> self>.size> > >def> __contains__(>self>, key):> >try>:> >self>.search(key)> >return> True> >except> KeyError:> >return> False> > > # Driver code> if> __name__>=>=> '__main__'>:> > ># Create a hash table with> ># a capacity of 5> >ht>=> HashTable(>5>)> > ># Add some key-value pairs> ># to the hash table> >ht.insert(>'apple'>,>3>)> >ht.insert(>'banana'>,>2>)> >ht.insert(>'cherry'>,>5>)> > ># Check if the hash table> ># contains a key> >print>(>'apple'> in> ht)># True> >print>(>'durian'> in> ht)># False> > ># Get the value for a key> >print>(ht.search(>'banana'>))># 2> > ># Update the value for a key> >ht.insert(>'banana'>,>4>)> >print>(ht.search(>'banana'>))># 4> > >ht.remove(>'apple'>)> ># Check the size of the hash table> >print>(>len>(ht))># 3>

>

>

出力

True False 2 4 3>

時間の複雑さと空間の複雑さ:

  • 時間の複雑さ入れる検索 そして 取り除く 個別のチェーンを使用するハッシュ テーブル内のメソッドは、ハッシュ テーブルのサイズ、ハッシュ テーブル内のキーと値のペアの数、および各インデックスでのリンク リストの長さに依存します。
  • 適切なハッシュ関数とキーの均一な分散を仮定すると、これらのメソッドの予想時間計算量は次のようになります。 ○(1) 操作ごとに。ただし、最悪の場合、時間計算量が大幅に増加する可能性があります。 の上) ここで、n はハッシュ テーブル内のキーと値のペアの数です。
  • ただし、衝突の可能性を最小限に抑え、良好なパフォーマンスを確保するには、適切なハッシュ関数とハッシュ テーブルの適切なサイズを選択することが重要です。
  • 空間の複雑さ 個別のチェーンを使用したハッシュ テーブルのサイズは、ハッシュ テーブルのサイズと、ハッシュ テーブルに格納されているキーと値のペアの数によって異なります。
  • ハッシュテーブル自体は オ(メートル) space、m はハッシュ テーブルの容量です。各リンク リスト ノードは、 ○(1) スペースが必要であり、リンク リストには最大で n 個のノードを含めることができます。ここで、n はハッシュ テーブルに格納されているキーと値のペアの数です。
  • したがって、空間の総複雑さは次のようになります。 O(m + n)

結論:

実際には、スペースの使用量と衝突の可能性のバランスをとるために、ハッシュ テーブルの適切な容量を選択することが重要です。容量が小さすぎると衝突の可能性が高まり、パフォーマンスが低下する可能性があります。一方、容量が大きすぎると、ハッシュ テーブルが必要以上にメモリを消費する可能性があります。