HashMap is one of the most commonly used data structures to find and delete elements with an O (1) time complexity.
This article will use a simple example to explain how the hashmap inside the Scala language works, and look at how get and put work. usage Examples
def main (args:array[string]): unit = {
val m = mutable. Hashmap[string,int] ()
m.put ("a", 1)
m.put ("B", 2)
println ("M:" +m)
println ("a=" +m.get ("a"))
For ((k,v) <-m) {//Traversal mode
print (k,v)
}
}
output results:
M:map (b-> 2, a-> 1)
a=some (1)
(b,2) (a,1)
HashMap Realization Principle
1. Data Structure
HashMap is the combination of array and linked list, where the hash value of the key is the subscript of the array, the same hash value key is stored as a linked list.
Where the array is in table, where the table array stores the objects of the entry class,
The key of entry is HashMap, value is HashMap, and next is the next entry element
@transient protected Var table:array[hashentry[a, Entry]] = new Array (initialcapacity)
trait hashentry [A, E] {
V Al key:a
var next:e = _
}
final class Defaultentry[a, B] (Val key:a, var value:b)
extends Hashentry[a, Defaultentry[a, B]] with Serializable
{
override def toString = chainstring
def chainstring = {
"(kv:" + Key + "," + Value + ")" + (if (next!= null) "->" + next.tostring Else "")
}
}
2. Put method
Let's take a look at the put code implementation:
override def put (Key:a, value:b): option[b] = {val E = findoraddentry (key, value) if (e eq null) None else {val v = e.value; e.value = value;
Some (v)}///If key exists update its value value}/** find entry with given key in table, or add new one if not found.
* May is somewhat faster then ' findentry '/' addentry ' pair as it * computes entry ' s hash index only once.
* Returns entry found in table or null.
* New entries are created by calling ' Createnewentry ' method. */protected Def Findoraddentry[b] (key:a, value:b): Entry = {val h = index (Elemhashcode (key))//Get the number calculated by the hash value Subscript val e = findEntry0 (key, h)//To find whether value exists by subscript and key if (e ne null) e else {addEntry0 createnewentry (key, Val UE), h);
NULL}} Private[this] def findEntry0 (Key:a, h:int): Entry = {var e = table (h). Asinstanceof[entry] while (e!= null &&!elemequals (E.key, key)) E = E.next e}
First, we need to calculate the subscript h of the table array according to HashMap key keys.
And then find the H element e in the table, and when E is not empty and E's key and HashMap's key is the same, assign E's next to E
The last e returned, if not NULL, indicates that the key exists, returns the entry object, and updates its value
If E is empty, add
Protected def Createnewentry[b] (key:a, value:b): Entry
private[this] def addEntry0 (E:entry, h:int) {
E.next = Table (h). Asinstanceof[entry]//E As the head node of the linked list table
(h) = e
tablesize = tablesize + 1
nnsizemapadd (h)
if ( Tablesize > Threshold)
Resize (2 * table.length)
}
Each time you add an element, Tablesize adds one, representing the total number of elements, the result of the size method return
Override Def Size:int = Tablesize
Protected def elemhashcode (key:keytype) = key.##
# #是一个方法 #
# (): Int
Returns the Hascode of an object, and the Hascode method distinguishes:
For Numerics, it returns a hash value that is the same as the value.
For null, returns a hashcode, and Hashcode throws NullPointerException. 2, table expansion
When the elements in the HashMap are more and more, the probability of hash conflict is increasing, because the length of the array is fixed.
So in order to improve the efficiency of the query, we need to enlarge the HashMap array,
This is a common operation, and after the HashMap array has been expanded, the most performance-consuming points appear:
The data in the original array must recalculate its position in the new array and put it in, which is resize.
So when will hashmap be enlarged? When the number of elements in the HashMap exceeds the array size threshold,
An array expansion is performed, and the default value of threshold is 0.75 of the table size, which is a compromise value.
That is, by default, the array size is 16, so when the number of elements in the HashMap exceeds the 16*0.75=12,
It expands the size of the array to 2*16=32, which expands by one fold, and then recalculates the position of each element in the array, which is a very performance-consuming operation,
Private def resize (newsize:int) {
val oldtable = table
table = new Array (newsize)
Nnsizemapreset ( table.length)
var i = oldtable.length-1 while
(i >= 0) {
var e = oldtable (i) while
(e!= null) {
Val h = index (Elemhashcode (E.key))
val e1 = e.next
e.next = Table (h). asinstanceof[entry]
table (h) = E
e = E1
nnsizemapadd (h)
}
i = I-1
}
threshold = Newthreshold (_loadfactor, newsize)
}
Private[collection] Final def defaultloadfactor:int = 750//corresponds to 75%
private[collection] Final def LOADFA Ctordenum = 1000//should be loadfactordenom, but changing that isn ' t binary compatible private[collection
] Final de F Newthreshold (_loadfactor:int, size:int) =
((Size.tolong * _loadfactor)/loadfactordenum). ToInt // The new threshold is twice times the size of 75% before the expansion.
3, Get method
The Get method is much simpler when you understand the put operation, and getting is just one step in the take operation.
def get (KEY:A): option[b] = {
val e = findentry (key)
if (e eq null) None
else Some (e.value)
}
Protect Ed def findentry (key:a): Entry =
findEntry0 (key, Index (Elemhashcode (key))
Summary
HashMap is a hash table that stores content that is a key-value pair (key-value) mapping.
The implementation of the HASHMAP is not synchronized, which means that it is not thread-safe. Its key, value can be null. In addition, the mappings in HashMap are not ordered.
The implementation of HashMap is realized by means of hash table hashtable