LRUアルゴリズムを使用すると、実際にデータ構造を設計できます。最初に、容量パラメーターをキャッシュの最大容量として受け取る必要があります。次に、2つのAPIを実装します。1つはキーと値のペアを格納するput(key、val)メソッドで、もう1つはget(key )メソッドはキーに対応するvalを取得し、キーが存在しない場合は-1を返します。
getおよびputメソッドはO(1)時間の複雑さでなければならないことに注意してください。具体的な例を見て、LRUアルゴリズムがどのように機能するかを見てみましょう。
/ *キャッシュ容量は2です* / LRUCache cache = new LRUCache(2 ); // キャッシュをキューとして理解できます // 左側がチームの先頭であり、右側がチームの末尾であると想定します /// 最近使用されたキューがキューの先頭にあり ます 行末で使用 // 括弧はキーと値のペア(キー、値)を示します cache.put( 1、1 ); // cache = [(1、1 )] cache.put( 2、2 ); // cache = [(2、2)、(1、1 )] cache.get( 1); // 1を返す // cache = [(1、1)、(2、2 )] //説明:最近のアクセスのためキー1がなくなっているため、キューの先頭に進みます //キー1に対応する値を返します 1 cache.put( 3、3 ); // cache = [(3、3)、(1、1 )] // 説明:キャッシュ容量完全、コンテンツを削除してスペースを確保する必要がある // 優先度は、長期間使用されていないデータ、つまり、チームの最後のデータを削除し、 // 新しいデータをキューヘッドに挿入します cache.get( 2); // -1を返します(見つかりません) // cache = [(3、3 )、(1、1 )] //説明:キャッシュにキーが2のデータはありません cache.put( 1、4 ); // cache = [(1、4)、(3、3 )] //説明:キー1は既に存在します。元の値1から4を上書きします //キーと値のペアをチームの責任者に渡すことを忘れないでください
上記の操作プロセスを分析して、putメソッドとgetメソッドの時間の複雑さをO(1)にするために、キャッシュデータ構造の必要な条件をまとめることができます。
最近使用されたデータと長期間使用されたデータを区別するためにキャッシュを順序付ける必要があることは明らかであるため、キーがすでにキャッシュに存在するかどうかを確認する必要があります。容量がいっぱいの場合は、最後のデータを削除する必要があります。データを挿入するたびにチームの頭に。
では、どのデータ構造が上記の条件を同時に満たすのでしょうか?ハッシュテーブルの検索は高速ですが、データの順序は固定されていません。リンクリストには順序があり、挿入と削除は高速ですが、検索は低速です。それらを組み合わせて、新しいデータ構造、ハッシュリンクリストを形成します。
LRUキャッシュアルゴリズムのコアデータ構造は、ハッシュリンクリスト、二重リンクリスト、およびハッシュテーブルの組み合わせです。このデータ構造は次のようになります。
削除操作が必要です。ノードを削除するには、ノード自体のポインターが必要なだけでなく、その先行ノードのポインターも操作する必要があります。また、二重リンクリストは、先行ノードの直接検索をサポートできるため、操作の時間の複雑さが保証されますO(1)。
'' ' メソッド1 クラスLRUCache: #@ param capacity、integer def __init __(self、capacity): self.cache =() self.used_list = [] self.capacity = capacity #@ return integer def get(self、 key): if key in self.cache:if リストを使用してアクセスの順序を記録すると、最初にアクセスしたものがリストの前に配置され、最後にアクセスしたものがリストの後ろに配置されるため、キャッシュがいっぱいになると、リストを削除します[0 ]、そして新しいアイテムを挿入します; if key!= Self.used_list [-1]: self.used_list.remove(key) self.used_list.append(key) return self.cache [key] else: return -1 def put( self、key、value): self.cacheのキーの場合: self.used_list.remove(key) elif len(self.cache)== self.capacity: self.cache.pop(self.used_list.pop(0)) self.used_list.append(key) self.cache [key]値= 「」「 #の方法2: インポートコレクション #基づいorderedDict実装 クラスがLRUCache(collections.OrderedDict): 」「」 機能:最低使用頻度アルゴリズムcollection.OrdereDictを使用してタイプデータ OrdereDict特別な方法popitemを有する(最終= Falseの場合、キューが実装され、最初に挿入された要素 がポップされます。Last = Trueの場合、スタックメソッドが実装され、最後に挿入された要素がポップされます。 2つのメソッドが実装されています:get(キー)はキーの対応する値を取り出し、それがNone set(key、value)を返さない場合、より多くのLRU特性を持ち、要素を追加します '' ' def __init__(self、size = 5): Self.sizeは = サイズ self.cache = collections.OrderedDict() #は、注文した辞書 DEF GET(セルフ、キー): IFキーでself.cache.keys(): #も同時に訪問来院時に記録しているため番号(オーダー) 値= self.cache.pop(キー) #の保証リストの最近の訪問は、最終的な表面に常にある self.cache [キー] = 値の 戻り値は 、他: 値 = なし 戻り値 DEFのPUT(セルフ、キー、値): もしキーでself.cache.keys(): self.cache.pop(キー) self.cache [キー] = 値 のelif self.size == LEN(self.cache): self.cache.popitem(ラスト = False)が 自己.cache [キー] = 値 他: self.cache [キー] = 値 場合 __name__ == ' __main__ ' : 試験 = LRUCache() test.put(' '、1 ) test.put('b '、2 ) test.put(' c '、3 ) test.put(' d '、4 ) test.put(' e '、5 ) #test.put(' f '、6) print(test。 get(' a '))
リファレンス:https : //blog.csdn.net/qq_35810838/article/details/83035759
https://labuladong.gitbook.io/algo/gao-pin-mian-shi-xi-lie/lru-suan-fa