基本型のデータ構造、配列、およびリンクされたリストをよく使用しますが、それぞれに独自の利点があります。配列: 挿入時間の複雑さは高く、検索時間の複雑さは低い. リンクされたリストに関しては、その逆です. 一般に、データ構造は、ルックアップと挿入の使用量に基づいて決定されます。ただし、文字列を与えられて各文字の出現回数を数えると、いくつか問題があることがわかります.この場合は、hashMap (ハッシュ テーブル)を使用できます。
1.原則:
配列とリンク リストの利点を組み合わせて、格納場所を探すときに配列を使用し、格納するときにリンク リストを使用して、時間の複雑さを大幅に軽減します。
1. リンク リスト linkList を作成します。
ここでの連結リストは実際には以前の一方向連結リストとほとんど同じですが、違いは連結リストの属性、組み込みのハッシュ値、および組み込みのジェネリック <K, V> (キー価値)。
public class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
hash:ハッシュ関数。ハッシュ アルゴリズムによって固定長の出力に変換され、出力はハッシュ値になります。
特別なことは、ハッシュ値がほぼ一意であり、キーの int 値として使用できることです。このペアは、将来的に大きな影響を与えます^_^.
2. リンク リスト配列 linkListArr を作成します。
これは詳細に入る必要はありません。操作は非常に簡単ですが、配列を作成するときにリンクされたリストを初期化することを忘れないでください。
3. 使い方:
getHash (ハッシュ値を取得) : .hashCode()
put (配置):ここで、hashMap の優位性を反映できます。Key 値は任意の型であるため、これを使用して getHash() メソッドを介してキーのハッシュ値を取得し、それを長さと比較しますリンクされたリスト配列 AND 演算は、配列の長さを超えないことが保証されています
int storeIndex = getHash(key) & len - 1 ;
このように簡単に格納場所を求めることができますが、計算後の格納添字が同じ場合はどうなるかという問題が残ります。
このとき、連結リストの利点が反映され、連結リストの末尾に簡単に追加できるので、両者を併用することで効率が大幅に向上します。
get (取得): put() のアイデアに従って、単純に推測し、キーを使用してストレージ添字を計算し、以下の対応する表を 1 つずつ検索することもできます。
Java ソースコードの作成: (hashMap の最も重要な部分に属し、効率を最大化します):
final Node<K,V> getNode(int hash, Object key) {//查找节点,需要hash 和 key 一起,提高效率
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {//table 为链表数组 得到需要的存储下标
if (first.hash == hash && // 总是想核对头节点
((k = first.key) == key || (key != null && key.equals(k))))//只有在hash值相等情况下,才会去判断key是否相等(先比较地址是否相同,不相同后才比较值),以提高效率(因为hash值相等概率极小,而且比较两个int数据快得多)
return first;
if ((e = first.next) != null) {//安全性检验,查看后面是否右节点
if (first instanceof TreeNode)//由于相同的key值过多,链表显得过于冗长,所以源代码中会将链表变成一棵“树”,方便查找
return ((TreeNode<K,V>)first).getTreeNode(hash, key)//树内查找方式;
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);//不断循环查找
}
}
return null;
}