Java interview questions set map

Set

Set focuses on the unique nature . This system set is used to store unordered elements ( the order of deposit and withdrawal is not necessarily the same ) , and the value cannot be repeated. right

The essence of object equality is judged by the object  hashCode value ( java calculates this sequence number based on the memory address of the object), if you want

To make two different objects equal, you must override  the Object 's  hashCode method and  equals method. HashSet ( Hash table)

The side of the hash table stores the hash value. The order in which HashSet stores elements is not in the order in which they were stored ( obviously different from  List ) but

It is stored according to the hash value, so the fetched data is also obtained according to the hash value. The hash value of the element is obtained through the hashcode method of the element

Yes , HashSet first judges the hash value of two elements, if the hash value is the same, then compares the equals method if the result of  equls is

true , the HashSet is treated as the same element. Not the same element if  equals is  false .

How to store the elements with the same hash value  equals to  false , that is, to postpone under the same hash value (you can think of elements with the same hash value

element in a hash bucket). That is, store a column like a hash. Figure  1 shows the situation where  the hashCode values ​​are different; Figure  2 shows

The hashCode values ​​are the same, but  the equals are not the same.

HashSet determines the location of elements in memory by  hashCode value. Multiple elements can be stored in one  hashCode position.

TreeSet (binary tree)

1. TreeSet() uses the principle of binary tree to sort the objects of the new  add() in the specified order (ascending order, descending order), each additional

Objects are sorted and inserted into the specified position of the binary tree.

2. Both Integer and  String objects can be sorted by the default  TreeSet , but objects of custom classes are not allowed, and you can define them yourself

The class must implement the  Comparable interface and override the corresponding  compareTo() function before it can be used normally.

3. When overriding  the compare() function, it is necessary to return the corresponding value to make  the TreeSet sorted according to certain rules

4. Compares the order of this object with the specified object. If the object is less than, equal to, or greater than the specified object, returns a negative integer, zero, or

positive integer.

LinkHashSet ( HashSet+LinkedHashMap ) For LinkedHashSet, it inherits from HashSetand isimplemented LinkedHashMap

The bottom layer of LinkedHashSet uses  LinkedHashMap to save all elements, it inherits from  HashSet , and all its methods operate

It is the same as  HashSet , so the implementation of  LinkedHashSet is very simple, only four construction methods are provided, and by passing a

An identification parameter, calls the constructor of the parent class, and constructs a  LinkedHashMap at the bottom layer to realize it, and it is related to the parent class in related operations

The operation of HashSet is the same, just call the method of the parent class  HashSet directly .

Map

HashMap (array + linked list + red-black tree)

HashMap stores data according to  the hashCode value of the key . In most cases, its value can be directly located, so it has fast access.

Ask about speed, but the order of traversal is uncertain.  HashMap only allows the key of one record to be null at most , and the value of multiple records is allowed

null . HashMap is not thread-safe, that is, multiple threads can write  HashMap at the same time at any time , which may cause data inconsistency

Sincerely. If you need to meet thread safety, you can use  the synchronizedMap method of  Collections to make  HashMap thread-safe

capabilities, or use  ConcurrentHashMap . We use the following picture to introduce

The structure of HashMap .

JAVA7 implementation

In the general direction, HashMap is an array, and each element in the array is a one-way linked list. In the figure above, each green

The entity is an instance of the nested class  Entry , and Entry contains four attributes: key, value, hash value and  next for a one-way linked list .

1. capacity : The current array capacity is always  2^n , and can be expanded. After expansion, the array size is  twice the current size .

2. loadFactor : load factor, the default is  0.75 . 3. threshold : The threshold of expansion, equal to  capacity * loadFactor

JAVA8 implementation

Java8 has made some modifications to  HashMap . The biggest difference is the use of red-black tree, so it is composed of array + linked list + red-black tree

become.

According to the introduction of  Java7 HashMap , we know that when searching, we can quickly locate the specific location of the array according to  the hash value.

mark, but after that, we need to compare one by one along the linked list to find what we need. The time complexity depends on

Due to the length of the linked list, it is  O(n) . In order to reduce the overhead of this part, in  Java8 , when the number of elements in the linked list exceeds  8 , the

The linked list is converted into a red-black tree, and the time complexity can be reduced to  O(logN) when searching in these positions .

ConcurrentHashMap

Segment segment

The ideas of ConcurrentHashMap and  HashMap are similar, but because it supports concurrent operations, it is more complicated. all

A  ConcurrentHashMap is composed of  Segments , and Segment means " part " or " a section " , so many

Both parties will describe it as a segment lock. Note that in the text, I used " slot " to represent a  segment in many places .

Thread safety ( Segment inherits ReentrantLock and locks)

A simple understanding is that ConcurrentHashMap is a  Segment array, and Segment is implemented by inheriting  ReentrantLock

Rows are locked, so each operation that needs to be locked locks a  segment , so as long as each  segment is thread-safe

, it also achieves global thread safety. Parallelism  concurrencyLevel : parallel level, concurrency number, segment number, how to translate is not important, understand it. The default is  16 ,

That is to say,  ConcurrentHashMap has  16  Segments , so in theory, at this time, it can support up to  16 segments at the same time

Threads write concurrently, as long as their operations are distributed on different  segments . This value can be set to other values ​​during initialization

value, but once initialized, it cannot be expanded. And then specifically to the interior of each  segment , in fact, each  segment is very similar

 The HashMap introduced before , but it must ensure thread safety, so it is more troublesome to deal with.

Java8 implementation (introduced red-black tree)

Java8 has made relatively large changes to  ConcurrentHashMap , and Java8 has also introduced red-black trees.

Java8 implementation (../../../../../0 horse soldier / new folder /BAT interview assault data (1)/ organization /BAT interview assault data /06-JAVA interview

Collation of core knowledge points ( students with more time to review comprehensively ).assets/Java8 implementation ( introduced red-black tree ).jpg)

HashTable (thread-safe)

Hashtable is a legacy class, and many common functions of mapping are similar to  HashMap , the difference is that it inherits from  the Dictionary class, and is

Thread-safe, only one thread can write  Hashtable at any time , and the concurrency is not as good as  ConcurrentHashMap , because

ConcurrentHashMap introduces segment locks. Hashtable is not recommended to be used in new code, it can be used when thread safety is not required

Replace it with  HashMap , and use  ConcurrentHashMap when thread safety is required .

3.4.4. TreeMap (sortable)

TreeMap implements  the SortedMap interface, which can sort the records it saves according to the key. The default is the ascending order of the key value, and it can also be

Specify the comparator for sorting. When traversing  the TreeMap with  Iterator , the records obtained are sorted. If using a sorted map,

It is recommended to use  TreeMap .

When using  TreeMap , the key must implement the  Comparable interface or pass in a custom one when constructing  the TreeMap

Comparator , otherwise an exception of type  java.lang.ClassCastException will be thrown at runtime .

LinkHashMap (record insertion order)

LinkedHashMap is a subclass of  HashMap , which saves the insertion order of records, and uses  Iterator to traverse

When LinkedHashMap is used, the record obtained first must be inserted first, and it can also be constructed with parameters and sorted according to the access order. The implementation of TreeMap is a red-black tree data structure, that is to say, a self-balancing sorted binary tree, so that it can ensure fast

Retrieves the specified node.

The relationship between TreeSet and  TreeMap

In order to let everyone understand the relationship between  TreeMap and  TreeSet , let's look at part of the source code of the  TreeSet class:

public class TreeSet<E> extends AbstractSet<E>

implements NavigableSet<E>, Cloneable, java.io.Serializable

{

// Use the key of NavigableMap to save the elements of the Set collection

private transient NavigableMap<E,Object> m;

// Use a PRESENT as all values ​​of the Map collection .

private static final Object PRESENT = new Object();

// Constructor for package access rights, create a Set collection with the specified NavigableMap object

TreeSet(NavigableMap<E,Object> m)

{

this.m = m;

}

public TreeSet() //

{

// Create a new TreeMap in natural order ,

// Create a TreeSet based on the TreeSet ,

// Use the key of the TreeMap to save the elements of the Set collection

this(new TreeMap<E,Object>());

}

public TreeSet(Comparator<? super E> comparator) //

{

// Create a new TreeMap with custom sorting ,

// Create a TreeSet based on the TreeSet ,

// Use the key of the TreeMap to save the elements of the Set collection

this(new TreeMap<E,Object>(comparator));

}

public TreeSet(Collection<? extends E> c)

{

// Call the No. constructor to create a TreeSet , and the bottom layer uses TreeMap to save the collection elements

this();

// Add all elements in the Collection collection c to the TreeSet

addAll(c);

}

public TreeSet(SortedSet<E> s)

{

// Call the No. constructor to create a TreeSet , and the bottom layer uses TreeMap to save the collection elements

this(s.comparator());

// Add all elements in the SortedSet collection s to the TreeSet

addAll(s);

}

// Other methods of TreeSet just call the method of TreeMap directly to provide implementation

...

public boolean addAll(Collection<? extends E> c)

{

if (m.size() == 0 && c.size() > 0 &&

c instanceof SortedSet &&

m instanceof TreeMap)

{// Forcibly convert the c collection to the SortedSet collection

SortedSet<? extends E> set = (SortedSet<? extends E>) c;

// Forcibly convert the m collection to a TreeMap collection

TreeMap<E,Object> map = (TreeMap<E, Object>) m;

Comparator<? super E> cc = (Comparator<? super E>) set.comparator();

Comparator<? super E> mc = map.comparator();

// If the two Comparators cc and mc are equal

if (cc == mc || (cc != null && cc.equals(mc)))

{

// Add all the elements in the Collection as the key of the TreeMap collection

map.addAllForTreeSet(set, PRESENT);

return true;

}

}

// Directly call the addAll() method of the parent class to implement

return super.addAll(c);

}

...

}

display more

As can be seen from the above code, the ① and ② constructors of TreeSet both create a new  TreeMap as the actual storage of  Set elements

container, while the other  two constructors depend on constructors ① and ② respectively. It can be seen that the storage actually used at the bottom of the TreeSet

The storage container is  TreeMap .

Completely similar to  HashSet , most of the methods in TreeSet are implemented by directly calling the methods of  TreeMap .

Readers can refer to the source code of  TreeSet by themselves , so it will not be given here.

For  TreeMap , it uses a sorted binary tree called " red-black tree " to save each Entry in  the Map  - each

Entry is treated as a node of the " red-black tree " . For example, for the following program:

public class TreeMapTest

{

public static void main(String[] args)

{

TreeMap<String , Double> map =

new TreeMap<String , Double>();

map.put("ccc" , 89.0);

map.put("aaa" , 80.0);

map.put("zzz" , 80.0);

map.put("bbb" , 89.0);

System.out.println(map);

}

}

display more

When the program executes  map.put(“ccc”, 89.0);, the system will directly put the  Entry  “ccc”-89.0 into  the Map , and this  Entry

It is the root node of the " red-black tree " . Then the program executes  map.put(“aaa”, 80.0);, the program will add  “aaa”-80.0 as a new node

Add to the existing red-black tree.

In the future, every time a  key-value pair is added to  the TreeMap , the system needs to treat  the Entry as a new node and add it to the existing red and black nodes.

In the tree, in this way, it can be guaranteed that all  keys in  the TreeMap are always arranged from small to large. For example, if we output the above program, the

See the following results (all  keys are arranged from small to large):

{aaa=80.0, bbb=89.0, ccc=89.0, zzz=80.0} Show more

Adding Nodes to TreeMap

For  TreeMap , because it uses a " red-black tree " at the bottom to save  the Entry in the collection , it means that the  TreeMap adds elements

The performance of extracting elements and extracting elements is lower than that  of HashMap : when  TreeMap adds elements, it needs to loop through to find the insertion of the newly added  Entry

position, so it consumes more performance; when taking out elements from  the TreeMap , it needs to go through a loop to find the appropriate  Entry , which is also more expensive

performance. But the advantages of  TreeMap and TreeSet over  HashMap and HashSet are: All  entries in TreeMap are always pressed

The key is kept in an ordered state according to the specified sorting rule, and all elements in the TreeSet are always kept in an ordered state according to the specified sorting rule.

red black tree

A red-black tree is a self-balancing sorted binary tree. The value of each node in the tree is greater than or equal to the value of all nodes in its left subtree.

value, and less than or equal to the value of all nodes in its right subtree, which ensures that the red-black tree runtime can quickly search in the tree

and locate the desired nodes.

In order to understand the underlying implementation of  TreeMap , we must first introduce the two data structures of sorted binary tree and red-black tree. Among them, the red-black tree is another

A special kind of sorted binary tree.

Sorted binary tree is a special structure of binary tree, which can sort and retrieve all nodes in the tree very conveniently.

A sorted binary tree is either an empty binary tree or a binary tree with the following properties:

If its left subtree is not empty, the values ​​of all nodes on the left subtree are less than the value of its root node;

If its right subtree is not empty, the values ​​of all nodes on the right subtree are greater than the value of its root node;

Its left and right subtrees are also sorted binary trees.

Figure  1 shows a sorted binary tree:

Figure  1. Sorting binary tree For sorting a binary tree, if you traverse in order, you can get an ordered sequence from small to large. As 1, the binary tree can be traversed in order:

{23489910131518}

The steps of creating a sorted binary tree, that is, the process of continuously adding nodes to the sorted binary tree, the steps of adding nodes to the sorted binary tree are as follows

Down:

1. Start the search with the current node of the root node.

2. Compare the value of the new node with the value of the current node.

3. If the value of the new node is larger, use the right child node of the current node as the new current node; if the value of the new node is smaller, use the current node

The left child of the previous node becomes the new current node.

4. Repeat steps  2 and 3 until a suitable leaf node is found.

5. Add the new node as a child node of the leaf node found in step  4 ; if the new node is larger, add it as the right child node; otherwise add

is the left child node.

After mastering the above theory, let's analyze the process of adding nodes to  TreeMap (  Entry internal class is used to represent nodes in TreeMap )

Implementation,  the put(K key, V value) method of the TreeMap collection realizes putting  the Entry into the sorted binary tree. The source of the method is as follows

code:

public V put(K key, V value)

{

// First save the root node of the linked list with t

Entry<K,V> t = root;

// If t==null , it indicates an empty linked list, that is, there is no Entry in the TreeMap

if (t == null)

{

// Create an Entry with the new key-value , and use the Entry as root

root = new Entry<K,V>(key, value, null);

// Set the size of the Map collection to 1 , which means it contains an Entry

size = 1;

// Record number of modifications is 1

modCount++;

return null;

}

int cmp;

Entry<K,V> parent;

Comparator<? super K> cpr = comparator;

// If the comparator cpr is not null , it means that the custom sorting is adopted

if (cpr != null)

{

do {

// Use the Entry referenced by t after the last cycle of the parent

parent = t;

// Compare the newly inserted key with the key of t

cmp = cpr.compare(key, t.key);

// If the newly inserted key is less than the key of t , t is equal to the left node of t

if (cmp < 0)

t = t.left;

// If the newly inserted key is greater than the key of t , t is equal to the right node of t

else if (cmp > 0)

t = t.right;

// If the two keys are equal, the new value overwrites the original value ,

// and return the original value

else

return t.setValue(value);

} while (t != null); show more

The code in bold in the above program is the key algorithm to realize the " sorting binary tree " . Whenever the program wants to add a new node: the system always starts from the tree

The root node of the current node is compared  - that is, the root node is regarded as the current node, if the new node is greater than the current node, and the right child of the current node

If the point exists, the right child node is taken as the current node; if the newly added node is smaller than the current node, and the left child node of the current node exists, then

Take the left child node as the current node; if the new node is equal to the current node, overwrite the current node with the new node, and end the  loop——

Until the left and right child nodes of a certain node do not exist, add a new node to the child node of the node  - if the new node is larger than the node,

is added as the right child; if the new node is smaller than this node, it is added as the left child.

Delete node of TreeMap

When a program deletes a node from a sorted binary tree, in order to keep it as a sorted binary tree, the program must

for maintenance. Maintenance can be divided into the following situations:

1 ) The node to be deleted is a leaf node, you only need to delete it from its parent node.

2 ) The deleted node  p has only the left subtree, just add the left subtree  pL of  p to the left subtree of the parent node of  p ; the deleted node  p only has

If there is a right subtree, just add  p 's right subtree  pR to the right subtree of  p 's parent node.

3 ) If the left and right subtrees of the deleted node  p are not empty, there are two ways:

}

else

{

if (key == null)

throw new NullPointerException();

Comparable<? super K> k = (Comparable<? super K>) key;

do {

// Use the Entry referenced by t after the last cycle of the parent

parent = t;

// Compare the newly inserted key with the key of t

cmp = k.compareTo(t.key);

// If the newly inserted key is less than the key of t , t is equal to the left node of t

if (cmp < 0)

t = t.left;

// If the newly inserted key is greater than the key of t , t is equal to the right node of t

else if (cmp > 0)

t = t.right;

// If the two keys are equal, the new value overwrites the original value ,

// and return the original value

else

return t.setValue(value);

} while (t != null);

}

// Make the newly inserted node a child node of the parent node

Entry<K,V> e = new Entry<K,V>(key, value, parent);

// If the newly inserted key is less than the key of the parent , then e is the left child node of the parent

if (cmp < 0)

parent.left = e;

// If the newly inserted key is smaller than the parent 's key , then e is the right child node of the parent

else

parent.right = e;

// Repair the red-black tree

fixAfterInsertion(e); //

size++;

modCount++;

return null;

} Let  pL be the left or right child of  p 's parent  q (depending on whether  p is the left or right child of its parent  q ), and  pR be

The right child node of the inorder predecessor node  s of the p node ( s is the bottom right node of  pL , that is, the largest node in the  pL subtree).

Replace the node pointed to by  p with the in-order predecessor or successor of  p node, and then delete the in-order predecessor or successor node from the original sorted binary tree.

Can. (That is, replace the  p node with the smallest node larger than  p or the largest node smaller than  p ).

Figure  2 shows a schematic diagram of the deleted node with only the left subtree:

Figure  2. The deleted node has only the left subtree

Figure  3 shows a schematic diagram of the deleted node with only the right subtree:

Figure  3. The deleted node has only the right subtree

Figure  4 shows the situation that the deleted node has both left child nodes and right child nodes. At this time, we use the first method for maintenance:

Figure  4. The deleted node has both a left subtree and a right subtree

Figure  5 shows the situation where the deleted node has both a left subtree and a right subtree. At this time, we use the second method for maintenance: Figure  5. The deleted node has both a left subtree and a right subtree Tree

TreeMap deleted nodes are maintained using the situation on the right as shown in Figure  5 that is, the smallest node in the right subtree of the deleted node and the deleted node are used for maintenance.

It is maintained by deleting nodes and exchanging them.

The method of deleting nodes in TreeMap is implemented by the following method:

private void deleteEntry(Entry<K,V> p)

{

modCount++;

size--;

// If the left subtree and right subtree of the deleted node are both empty

if (p.left != null && p.right != null)

{

// Replace the p node with the inorder successor node of the p node

Entry<K,V> s = successor (p);

p.key = s.key;

p.value = s.value;

p = s;

}

// If the left node of the p node exists, replacement represents the left node; otherwise, it represents the right node.

Entry<K,V> replacement = (p.left != null ? p.left : p.right);

if (replacement != null)

{

replacement.parent = p.parent;

// If p has no parent node, replacemment becomes the parent node

if (p.parent == null)

root = replacement;

// If the p node is the left child of its parent node

else if (p == p.parent.left)

p.parent.left = replacement;

// If the p node is the right child of its parent node

else

p.parent.right = replacement;

p.left = p.right = p.parent = null;

// Repair the red-black tree

if (p.color == BLACK)

fixAfterDeletion(replacement); //

}

// If the p node has no parent node, show more

Guess you like

Origin blog.csdn.net/2301_76965813/article/details/130504181