目次
2. 内部ハッシュ: ハッシュ マッピング テクノロジー " >2. 内部ハッシュ: ハッシュ マッピング テクノロジー
3. マップの最適化" >3. マップの最適化
3.2、负载因子" >3.2、负载因子
最后" >最后
ホームページ Java &#&チュートリアル Java 改良章 (33)-----マップの概要

Java 改良章 (33)-----マップの概要

Feb 11, 2017 am 10:24 AM

前回のLZでは、HashMap、Hashtable、TreeMapの実装方法をデータ構造、実装原理、ソース解析の3つの側面から詳しく説明しました。

: 推奨読書: java改善の章(23) - hashmap

javaの増加の章(25) - -Hashtable

Java改善の章(26)-----hashCode

Java改善の章(27)--TreeMap

1. マップの概要

まず Map の構造図を見てください


Map:

「キーと値」マッピングの抽象インターフェイス。マップには重複キーは含まれておらず、1 つのキーが 1 つの値に対応します。 SortedMap:

Map インターフェースを継承する、順序付けされたキーと値のペアのインターフェース。 NavigableMap:

SortedMap を継承し、指定された検索ターゲットに最も近い一致のナビゲーション メソッドを返すインターフェイスを持ちます。 AbstractMap:

は、Map の関数インターフェイスのほとんどを実装します。 「Map実装クラス」の繰り返しコーディングを軽減します。 Dictionary:

キーを対応する値にマップするクラスの抽象親クラス。現在は Map インターフェイスに置き換えられています。 TreeMap:

順序付けされたハッシュ テーブルは、SortedMap インターフェイスを実装し、最下層は赤黒ツリーを通じて実装されます。 HashMap:

は、「ジッパーメソッド」に基づくハッシュテーブルです。最下層は「配列+リンクリスト」を使って実装されています。 WeakHashMap:

「ジッパーメソッド」に基づくハッシュテーブル。 HashTable:

「ジッパーメソッド」に基づくハッシュテーブル。 要約は次のとおりです:

それらの違い:

2. 内部ハッシュ: ハッシュ マッピング テクノロジー

ほぼすべての一般的なマップはハッシュ マッピング テクノロジーを使用します。私たちプログラマーはそれを理解する必要があります。

ハッシュ マッピング テクノロジーは、要素を配列にマッピングする非常にシンプルなテクノロジーです。ハッシュ マップは配列の結果を使用するため、任意のキーによる配列へのアクセスを決定するためのインデックス付けメカニズムが必要です。このメカニズムをハッシュ関数と呼びます。 Java では、そのような整数を見つけることについて心配する必要はありません。すべてのオブジェクトには整数値を返す hashCode メソッドが必要であり、必要なのはそれを整数に変換し、その値を配列で除算することだけです。サイズから余りを取り出します。以下の通り:

int hashValue = Maths.abs(obj.hashCode()) % size;
ログイン後にコピー

以下は HashMap と HashTable です:

----------HashMap------------
//计算hash值
static int hash(int h) {
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}
//计算key的索引位置
static int indexFor(int h, int length) {
        return h & (length-1);
}
-----HashTable--------------
int index = (hash & 0x7FFFFFFF) % tab.length;     //确认该key的索引位置
ログイン後にコピー

位置のインデックスは、配列内のノードの位置を表します。次の図は、ハッシュ マップの基本原理図です:


この図では、ステップ 1 ~ 4 は配列内の要素の位置を見つけること、ステップ 5 ~ 8 は配列内の要素の位置を見つけることです。要素を配列に追加します。挿入プロセス中に少しイライラすることがあります。同じハッシュ値を持つ複数の要素が存在する可能性があるため、それらは同じインデックス位置を取得します。これは、複数の要素が同じ位置にマッピングされることを意味します。このプロセスは「競合」と呼ばれます。競合を解決する方法は、インデックス位置にリンク リストを挿入し、このリンク リストに要素を追加するだけです。もちろん単純な挿入ではなく、インデックス位置のリンクリストを取得し、そうでない場合はその要素を直接挿入します。キーと同じである場合は、元のキーの値を上書きして古い値を返します。それ以外の場合、要素はチェーンの先頭に保存されます (最初に保存された要素はチェーンの最後に配置されます)。 。以下は HashMap の put メソッドで、インデックス位置を計算し、要素を適切な位置に挿入するプロセス全体を詳細に示しています:

public V put(K key, V value) {
        //当key为null,调用putForNullKey方法,保存null与table第一个位置中,这是HashMap允许为null的原因
        if (key == null)
            return putForNullKey(value);
        //计算key的hash值
        int hash = hash(key.hashCode());                 
        //计算key hash 值在 table 数组中的位置
        int i = indexFor(hash, table.length);            
        //从i出开始迭代 e,判断是否存在相同的key
        for (Entry<K, V> e = table[i]; e != null; e = e.next) {
            Object k;
            //判断该条链上是否有hash值相同的(key相同)
            //若存在相同,则直接覆盖value,返回旧value
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;    //旧值 = 新值
                e.value = value;
                e.recordAccess(this);
                return oldValue;     //返回旧值
            }
        }
        //修改次数增加1
        modCount++;
        //将key、value添加至i位置处
        addEntry(hash, key, value, i);
        return null;
    }
ログイン後にコピー

HashMap の put メソッドは、次の基本的な考え方を示しています。実際、他のマップを見ると、原則が似ていることがわかります。

3. マップの最適化

まず第一に、ハッシュマップの内部配列のサイズは 1 のみであり、すべての要素がこの位置 (0) にマッピングされると仮定します。より長いリンクリストを形成します。更新時やアクセス時にはこのリンクリストに対して線形探索を行う必要があるため、必然的に効率が悪くなってしまいます。非常に大きな配列があり、リンクされたリストの各位置に要素が 1 つしかない場合、アクセス時にインデックス値を計算してオブジェクトが取得されると想定します。これにより検索の効率は向上しますが、無駄が生じます。コントロール。確かに、これら 2 つの方法は極端ではありますが、最適化のアイデアを提供します。 要素が均等に分散されるように、より大きな配列を使用します。 Map には効率に影響する 2 つの要素があります。1 つはコンテナーの初期サイズで、もう 1 つは負荷率です。 3.1は、実装サイズを調整します。マップのサイズを調整できるようになります。マップ内の要素が一定量に達すると、コンテナ自体のサイズが変更されることはわかっていますが、このサイズ変更プロセスは非常にコストがかかります。サイズを変更するには、元の要素をすべて新しい配列に挿入する必要があります。インデックス = ハッシュ(キー) % の長さはわかっています。これにより、元の競合しているキーが競合しなくなり、競合していないキーが競合するようになる可能性があります。再計算、調整、挿入のプロセスは非常にコストがかかり、非効率的です。したがって、マップの予想されるサイズ値を把握し始めて、マップのサイズを十分に大きくすると、サイズ変更の必要性を大幅に削減、または排除することができ、速度が向上する可能性が高くなります。

以下は、HashMap がコンテナー サイズを調整するプロセスです。次のコードを通して、その拡張プロセスの複雑さを確認できます。
void resize(int newCapacity) {
            Entry[] oldTable = table;    //原始容器
            int oldCapacity = oldTable.length;    //原始容器大小
            if (oldCapacity == MAXIMUM_CAPACITY) {     //是否超过最大值:1073741824
                threshold = Integer.MAX_VALUE;
                return;
            }

            //新的数组:大小为 oldCapacity * 2
            Entry[] newTable = new Entry[newCapacity];    
            transfer(newTable, initHashSeedAsNeeded(newCapacity));
            table = newTable;
           /*
            * 重新计算阀值 =  newCapacity * loadFactor >  MAXIMUM_CAPACITY + 1 ? 
            *                         newCapacity * loadFactor :MAXIMUM_CAPACITY + 1
            */
            threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);   
        }
        
        //将元素插入到新数组中
        void transfer(Entry[] newTable, boolean rehash) {
            int newCapacity = newTable.length;
            for (Entry<K,V> e : table) {
                while(null != e) {
                    Entry<K,V> next = e.next;
                    if (rehash) {
                        e.hash = null == e.key ? 0 : hash(e.key);
                    }
                    int i = indexFor(e.hash, newCapacity);
                    e.next = newTable[i];
                    newTable[i] = e;
                    e = next;
                }
            }
        }
ログイン後にコピー

3.2、负载因子

         为了确认何时需要调整Map容器,Map使用了一个额外的参数并且粗略计算存储容器的密度。在Map调整大小之前,使用”负载因子”来指示Map将会承担的“负载量”,也就是它的负载程度,当容器中元素的数量达到了这个“负载量”,则Map将会进行扩容操作。负载因子、容量、Map大小之间的关系如下:负载因子 * 容量 > map大小  ----->调整Map大小。

         例如:如果负载因子大小为0.75(HashMap的默认值),默认容量为11,则 11 * 0.75 = 8.25 = 8,所以当我们容器中插入第八个元素的时候,Map就会调整大小。

        负载因子本身就是在控件和时间之间的折衷。当我使用较小的负载因子时,虽然降低了冲突的可能性,使得单个链表的长度减小了,加快了访问和更新的速度,但是它占用了更多的控件,使得数组中的大部分控件没有得到利用,元素分布比较稀疏,同时由于Map频繁的调整大小,可能会降低性能。但是如果负载因子过大,会使得元素分布比较紧凑,导致产生冲突的可能性加大,从而访问、更新速度较慢。所以我们一般推荐不更改负载因子的值,采用默认值0.75.

最后

        推荐阅读:

        java提高篇(二三)—–HashMap

        java提高篇(二五)—–HashTable

        Java提高篇(二六)-----hashCode

        Java提高篇(二七)—–TreeMap

 


以上就是Java提高篇(三三)-----Map总结的内容,更多相关内容请关注PHP中文网(www.php.cn)!


このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

PHP:Web開発の重要な言語 PHP:Web開発の重要な言語 Apr 13, 2025 am 12:08 AM

PHPは、サーバー側で広く使用されているスクリプト言語で、特にWeb開発に適しています。 1.PHPは、HTMLを埋め込み、HTTP要求と応答を処理し、さまざまなデータベースをサポートできます。 2.PHPは、ダイナミックWebコンテンツ、プロセスフォームデータ、アクセスデータベースなどを生成するために使用され、強力なコミュニティサポートとオープンソースリソースを備えています。 3。PHPは解釈された言語であり、実行プロセスには語彙分析、文法分析、編集、実行が含まれます。 4.PHPは、ユーザー登録システムなどの高度なアプリケーションについてMySQLと組み合わせることができます。 5。PHPをデバッグするときは、error_reporting()やvar_dump()などの関数を使用できます。 6. PHPコードを最適化して、キャッシュメカニズムを使用し、データベースクエリを最適化し、組み込み関数を使用します。 7

PHP対Python:違いを理解します PHP対Python:違いを理解します Apr 11, 2025 am 12:15 AM

PHP and Python each have their own advantages, and the choice should be based on project requirements. 1.PHPは、シンプルな構文と高い実行効率を備えたWeb開発に適しています。 2。Pythonは、簡潔な構文とリッチライブラリを備えたデータサイエンスと機械学習に適しています。

PHP対その他の言語:比較 PHP対その他の言語:比較 Apr 13, 2025 am 12:19 AM

PHPは、特に迅速な開発や動的なコンテンツの処理に適していますが、データサイエンスとエンタープライズレベルのアプリケーションには良くありません。 Pythonと比較して、PHPはWeb開発においてより多くの利点がありますが、データサイエンスの分野ではPythonほど良くありません。 Javaと比較して、PHPはエンタープライズレベルのアプリケーションでより悪化しますが、Web開発により柔軟性があります。 JavaScriptと比較して、PHPはバックエンド開発により簡潔ですが、フロントエンド開発のJavaScriptほど良くありません。

PHP対Python:コア機能と機能 PHP対Python:コア機能と機能 Apr 13, 2025 am 12:16 AM

PHPとPythonにはそれぞれ独自の利点があり、さまざまなシナリオに適しています。 1.PHPはWeb開発に適しており、組み込みのWebサーバーとRich Functionライブラリを提供します。 2。Pythonは、簡潔な構文と強力な標準ライブラリを備えたデータサイエンスと機械学習に適しています。選択するときは、プロジェクトの要件に基づいて決定する必要があります。

PHPの影響:Web開発など PHPの影響:Web開発など Apr 18, 2025 am 12:10 AM

phphassiblasifly-impactedwebdevevermentandsbeyondit.1)itpowersmajorplatformslikewordpratsandexcelsindatabase interactions.2)php'sadaptableability allowsitale forlargeapplicationsusingframeworkslikelavel.3)

PHP:多くのウェブサイトの基礎 PHP:多くのウェブサイトの基礎 Apr 13, 2025 am 12:07 AM

PHPが多くのWebサイトよりも優先テクノロジースタックである理由には、その使いやすさ、強力なコミュニティサポート、広範な使用が含まれます。 1)初心者に適した学習と使用が簡単です。 2)巨大な開発者コミュニティと豊富なリソースを持っています。 3)WordPress、Drupal、その他のプラットフォームで広く使用されています。 4)Webサーバーとしっかりと統合して、開発の展開を簡素化します。

PHP対Python:ユースケースとアプリケーション PHP対Python:ユースケースとアプリケーション Apr 17, 2025 am 12:23 AM

PHPはWeb開発およびコンテンツ管理システムに適しており、Pythonはデータサイエンス、機械学習、自動化スクリプトに適しています。 1.PHPは、高速でスケーラブルなWebサイトとアプリケーションの構築においてうまく機能し、WordPressなどのCMSで一般的に使用されます。 2。Pythonは、NumpyやTensorflowなどの豊富なライブラリを使用して、データサイエンスと機械学習の分野で驚くほどパフォーマンスを発揮しています。

See all articles