9.マップソースコードインタビュー質問コレクション

1. HashMapの基礎となるデータ構造は何ですか?
回答:HashMapの基礎となるデータ構造は、配列、リンクリスト、赤黒の木の組み合わせです。配列の主な機能は、迅速な検索を容易にすることです。時間の複雑さはO(1)、デフォルトサイズは16、配列の添え字インデックスはキーのハッシュコードです。計算。配列要素はノードと呼ばれます。複数のキーのハッシュコードが同じであるがキー値が異なる場合、単一のノードがリンクリストに変換されます。リンクリストのクエリの複雑さはO(n)です。リンクリストの長さが8以上で、配列のサイズが64を超える場合、リンクされたリストは赤黒ツリーに変換されます。赤黒ツリーのクエリの複雑さはO(log(n))です。簡単に言えば、最悪のクエリ時間は赤黒ツリーの最大深度に相当します。

2. HashMap、TreeMap、LinkedHashMapの違いは何ですか?
回答:3つすべてが特定の状況下で赤黒の木を使用し、基礎となるハッシュアルゴリズムは同じです。反復プロセス中に、マップのデータ構造が変更されると、ConcurrentModificationExceptionが報告されます。
違いは、HashMapデータ構造が主に配列であり、クエリが非常に高速であるということです。TreeMapデータ構造は主に赤黒ツリーです。赤黒ツリーの特性を使用して、左側が小さく、右側が大きく、キーの並べ替えを実現します。LinkedHashMapはHashMapに基づいています。リンクリストの構造が強化され、挿入順序アクセスと最小アクセス削除の2つの戦略が実現されます。3つのマップの基礎となるデータ構造が異なるため、3つの使用シナリオは異なります。TreeMapは、キーに従って並べ替える必要があるシーンに適しています。LinkedHashMapは、挿入順序に従ってアクセスするシーン、または最もアクセスの少ない要素を削除する必要があるシーンに適しています。残りのシーンはHashMapを使用します。

3.マップのハッシュアルゴリズムについて教えてください。
回答:ソースコードでは、ハッシュは次のコードで計算されます。最初にキーのハッシュコードが計算されます。キーはオブジェクトであるため、さまざまなタイプのキーに従ってハッシュコードが計算され、次にh ^(h >>> 16)が計算されます。これを行う利点は、計算されたハッシュ値がほとんどのシナリオで比較的分散していることを確認することです。
一般的に、ハッシュ値を計算した後、配列内の現在のキーのインデックス添え字位置を計算する必要があります。ここでは、モジュロ方式を採用しています。インデックス添え字位置=ハッシュ値%配列サイズ。計算されたインデックスが保証されるという利点があります。標準値はアレイの各インデックス位置に均等に分散されますが、モジュロ演算の計算は比較的遅くなります。数学には公式があります。bが2の累乗の場合、a%b = a&(b- 1)なので、ここでのインデックス位置の計算式は(n-1)&hashに置き換えることができます。

static final int hash(Object key) {
    
    
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

4.キー%配列サイズを使用しないのに、キーハッシュ値%配列サイズを使用する必要があるのはなぜですか?
回答:キーが数値の場合、キーの%配列サイズを直接使用しても問題はありませんが、キーは文字列または複合オブジェクトの場合もあります。現時点では、文字列または複合オブジェクトの%配列サイズの使用は受け入れられないため、最初に行う必要があります。キーのハッシュ値を計算します。

5.ハッシュ値を計算するときに、なぜ16ビットを右にシフトする必要があるのですか?
回答:ハッシュのアルゴリズムはh ^(h >>> 16)です。計算されたハッシュ値をより分散させるために、最初にhを16ビットで符号なしにシフトし、次にhとXORしてhを作成することを選択します。上位16ビットと下位16ビットの両方が計算に関与し、衝突の可能性を減らします。

6.モジュロ操作が&操作に置き換えられるのはなぜですか?
回答:key.hashCode()によって計算されたハッシュ値は、配列のインデックス添え字ではありません。インデックスの添え字位置をランダムに計算するには、ハッシュ値と配列のサイズを使用して係数を取得する必要があります。これにより、計算されたインデックス添え字分布が得られます。それはもっと均一になります。モジュロ操作プロセッサの計算は比較的遅く、数学的な証明によってサポートされる&操作に置き換えられ、プロセッサの処理速度が向上します。

7.アレイサイズが2の累乗であると主張されているのはなぜですか?
回答:サイズが2の累乗である場合にのみ、ハッシュ%n(配列サイズ)=(n-1)&ハッシュが真になります。

8. HashMapはどのように拡張されますか?
回答:拡張には2つの機会があります。1つは、書き込み中に配列が空であることが判明した場合と、初期化中に拡張が実行される場合です。デフォルトの拡張サイズは16です。次に、プットが成功した後、既存のアレイのサイズが拡張しきい値よりも大きいことが判明した場合、拡張が実行され、拡張は古いアレイのサイズの2倍になります。拡張のしきい値はしきい値です。しきい値は拡張のたびに再計算されます。しきい値は、アレイのサイズ*影響係数(0.75)に等しくなります。新しい配列が初期化された後、古い配列の値を新しい配列にコピーする必要があります。リンクされたリストと赤黒の木には、独自のコピー方法があります。

9.ハッシュの競合がある場合はどうすればよいですか?
回答:ハッシュの競合とは、キー値のハッシュコード計算が同じであるが、キー値が異なる状況を指します。バケットに要素が1つしかない場合、またはすでにリンクリストになっている場合は、新しい要素がリンクリストの最後に直接追加されます。バケット内の要素がすでにリンクリストであり、リンクリストの数が8以上の場合、現時点では2つの状況があります。この時点でアレイサイズが64未満の場合、アレイは再度展開され、リンクリストは赤黒ツリーに変換されません。配列サイズが64より大きい場合、リンクされたリストは赤黒の木に変換されます。ここでは、リンクされたリストの数が8以上であるかどうかを判断するだけでなく、配列のサイズも判断します。アレイ容量が64未満の理由はすぐには変換されません。赤黒ツリーが占めるスペースはリンクリストよりもはるかに大きく、変換にも時間がかかるため、アレイ容量が小さいと競合が深刻になります。

10.リンクリストの数が8以上の場合、リンクリストを赤黒ツリーに変換する必要があるのはなぜですか。
回答:リンクされたリストが多すぎると、トラバーサルにかかる時間が長くなります。赤黒ツリーに変換すると、トラバーサルの時間の複雑さを軽減できますが、赤黒ツリーに変換すると、変換にスペースと時間のかかるコストが発生します。これは、Poissonを通じて配布されます。公式計算では、通常の状況では、リンクされたリストの数が8になる確率は1,000万分の1未満であるため、通常の状況では、リンクされたリストは赤黒のツリーに変換されません。この設計の目的は、リンクされたリストの数が8以上の場合でも、すばやくトラバースできる異常な状況(ハッシュアルゴリズムが適用されないなど)を防ぐことです。

11.赤黒ツリーはいつリンクリストに変換されますか?
回答:ノード数が6以下の場合、赤黒ツリーは自動的にリンクリストに変換されます。主な考慮事項は、赤黒ツリーのスペースコストです。ノード数が6以下の場合リンクリストをトラバースすると非常に高速になるため、赤黒の木が再びリンクリストになります。

12. HashMapを配置するときに、キーが既に配列に存在し、値を上書きしたくない場合はどうすればよいですか?得られた値が空のときにデフォルト値に戻したい場合はどうすればよいですか?
回答:配列にキーがあり、値を上書きしたくない場合は、putIfAbsentメソッドを選択できます。このメソッドには組み込み変数onlyIfAbsentがあります。組み込みがtrueの場合、上書きされません。通常使用されるputメソッドである組み込みonlyIfAbsentがfalseの場合、上書きできます。 。
値を取得するときに、値が空でデフォルト値に戻したい場合は、getOrDefaultメソッドを使用できます。メソッドの最初のパラメーターはkeyで、2番目のパラメーターはmap.getOrDefault( "2"、 "0")のように返されるデフォルト値です。 、マップにキー2の値がない場合、デフォルトでは空ではなく0が返されます。

13. LinkedHashMapのLRUとはどういう意味で、どのように実装されていますか?
回答:LinkedHashMapでは最小アクセス削除戦略とも呼ばれるLRU(最近使用されていない)は、removeEldestEntryメソッドを介して特定の戦略を設定できるため、最もアクセスの少ない要素が適切なタイミングで削除されます。
putメソッドの実行の最後に、LinkedHashMapはこの戦略をチェックし、戦略が満たされた場合はヘッドノードを削除します。LinkedHashMapが取得されると、現在アクセスされているノードがリンクリストの最後に移動します。ゆっくりと、ヘッドノードが最も訪問されていない要素になります。

おすすめ

転載: blog.csdn.net/Jgx1214/article/details/109096678