getEntryUsingComparator
Copy the code

1. Class definition

public class TreeMap<K.V>
    extends AbstractMap<K.V>
    implements NavigableMap<K.V>, Cloneable.java.io.Serializable
Copy the code

You can see this in the class definition

  • TreeMap is a generic class
  • TreeMap inherits from AbstractMap
  • TreeMap implements NavigableMap, indicating that TreeMap is directional and supports navigation
  • TreeMap implements the Cloneable interface, indicating that TreeMap supports cloning
  • TreeMap implements the java.io.Serializable interface, indicating that TreeMap supports serialization

2. Field attributes

// The order of treemaps is determined by the comparator. If the comparator is empty, the order is determined by the comparator that comes with the key
private final Comparator<? super K> comparator;
// The root node, Entry is a red-black tree structure
private transient Entry<K,V> root;
// Number of nodes
private transient int size = 0;
// Modify statistics
private transient int modCount = 0;
// Cache the set of key-value pairs
private transient EntrySet entrySet;
// Cache key Set
private transient KeySet<K> navigableKeySet;
private transient NavigableMap<K,V> descendingMap;
Copy the code

You can see this in the field properties

  • TreeMap is a red-black tree structure
  • TreeMap holds the root node root

3. Construction method

// The default constructor
public TreeMap(a) {
    	// The comparator defaults to null
        comparator = null;
    }
// Pass in a comparator object
public TreeMap(Comparator<? super K> comparator) {
    	// Set the comparator
        this.comparator = comparator;
    }
// Pass in a Map object
public TreeMap(Map<? extends K, ? extends V> m) {
    	// Set the comparator to null
        comparator = null;
    	// Add Map object data
        putAll(m);
    }
// Pass a SortedMap object
public TreeMap(SortedMap<K, ? extends V> m) {
    	// Assign the SortedMap comparator to the current comparator
        comparator = m.comparator();
        try {
            // Add data to the SortedMap object
            buildFromSorted(m.size(), m.entrySet().iterator(), null.null);
        } catch (java.io.IOException cannotHappen) {
        } catch (ClassNotFoundException cannotHappen) {
        }
    }
Copy the code

You can see this in the constructor

  • TreeMap defaults to null and essentially uses the comparator that comes with the Key. If the default comparator is null, objects for the Key must implement the Comparable interface
  • TreeMap can be initialized by specifying a comparator
  • TreeMap can receive a Map object for initialization
  • TreeMap can receive a SortedMap object to initialize

Method 4.

The size method

// Get the number of elements
public int size(a) {
    	// Return the size of the cache
        return size;
    }
Copy the code

Either containsKey method

// Check whether the node corresponding to the key exists
public boolean containsKey(Object key) {
    	// getEntry is used to obtain the node corresponding to the key
        returngetEntry(key) ! =null;
    }
Copy the code

The get method

// Find the value based on the passed key
public V get(Object key) {
    	// Use getEntry to find the node corresponding to the key
        Entry<K,V> p = getEntry(key);
    	// Return null if the node does not exist, return value of the node
        return (p==null ? null : p.value);
    }
Copy the code

The getEntry method

// Get the corresponding node based on the passed key
final Entry<K,V> getEntry(Object key) {
        if(comparator ! =null)
            // If there is a comparator, call the getEntryUsingComparator method to find the node
            return getEntryUsingComparator(key);
    	// Check the validity of the key
        if (key == null)
            throw new NullPointerException();
    	// Objects for key must implement the Comparable interface
        @SuppressWarnings("unchecked")
            Comparable<? super K> k = (Comparable<? super K>) key;
    	// Get a copy of the root node
        Entry<K,V> p = root;
    	// Search through the while loop
        while(p ! =null) {
            //key for comparison
            int cmp = k.compareTo(p.key);
            if (cmp < 0)
                // If the key passed in is smaller than the key of the current node, look left
                // Point the current node to the left child node
                p = p.left;
            else if (cmp > 0)
                // If the key passed in is larger than the current node's key, look to the right
                // Point the current node to the right child node
                p = p.right;
            else
                // The current node is returned
                return p;
        }
    	// Not found, return null
        return null;
    }
Copy the code

GetEntryUsingComparator method

// Use TreeMap's built-in comparator to find nodes
final Entry<K,V> getEntryUsingComparator(Object key) {
        @SuppressWarnings("unchecked")
            K k = (K) key;
    	// Get a copy of the comparator
        Comparator<? super K> cpr = comparator;
        if(cpr ! =null) {
            // If the comparator is not null
            // Get a copy of the root node
            Entry<K,V> p = root;
            // Use the while loop to find
            while(p ! =null) {
                // Use TreeMap's built-in comparator for comparison
                int cmp = cpr.compare(k, p.key);
                if (cmp < 0)
                    // If the key passed in is smaller than the key of the current node, look left
                    // Point the current node to the left child node
                    p = p.left;
                else if (cmp > 0)
                    // If the key passed in is larger than the current node's key, look to the right
                    // Point the current node to the right child node
                    p = p.right;
                else
                    // The current node is returned
                    returnp; }}// Not found, return null
        return null;
    }
Copy the code

GetCeilingEntry method

// Returns a node that is only greater than or equal to the key passed in
final Entry<K,V> getCeilingEntry(K key) {
    	// Get a copy of the root node
        Entry<K,V> p = root;
    	// Exit the while loop with p null
        while(p ! =null) {
            // Compare the passed key with the current key traversing the node
            int cmp = compare(key, p.key);
            if (cmp < 0) {
                // If the key passed in is smaller than the key currently traversed by the node
                if(p.left ! =null)
                    If the left child of the current traversal node is not null, continue traversal to the left
                    // Refer the current traversal node to the left child node
                    p = p.left;
                else
                    // Smaller than the current node, but the current node does not have a left child node
                    return p;
            } else if (cmp > 0) {
                // If the key passed is greater than the key currently traversed the node
                if(p.right ! =null) {
                    // If the right child of the current traversal node is not null, continue traversal to the right
                    // Point the current traversal node to the right child node
                    p = p.right;
                } else {
                    // If the current traversal node right child node is null
                    // Get the parent of the current traversal node
                    Entry<K,V> parent = p.parent;
                    // A copy of the node currently traversed
                    Entry<K,V> ch = p;
                    // the while loop iterates
                    // The parent node is the left child of the grandfather node
                    while(parent ! =null && ch == parent.right) {
                        ch = parent;
                        parent = parent.parent;
                    }
                    // returns the grandfather node
                    returnparent; }}else
                // The passed key is equal to the current traversal node key, returns the current node
                return p;
        }
        return null;
    }
Copy the code

GetFloorEntry method

// Returns a node that is only less than or equal to the key passed in
final Entry<K,V> getFloorEntry(K key) {
    	// Get a copy of the root node
        Entry<K,V> p = root;
    	// Exit the while loop with p null
        while(p ! =null) {
            // Compare the passed key with the current key traversing the node
            int cmp = compare(key, p.key);
            if (cmp > 0) {
                // If the key passed is greater than the key currently traversed the node
                if(p.right ! =null)
                    // If the key currently traversed has a right child, continue traversing to the right
                    // Point the current traversal node to the right child node
                    p = p.right;
                else
                    // If the current traversal node does not have a right child, returns the current traversal node
                    return p;
            } else if (cmp < 0) {
                // If the key passed in is smaller than the key currently traversed by the node
                if(p.left ! =null) {
                    If the left child of the current traversal node is not null, continue traversal to the left
                    // The current traversal node refers to the left child
                    p = p.left;
                } else {
                    // If the left child of the current traversal node is null
                    // Get the parent of the current traversal node
                    Entry<K,V> parent = p.parent;
                     // A copy of the node currently traversed
                    Entry<K,V> ch = p;
                    // the while loop iterates
                    // Look up until the parent node is the right child of the grandfather node
                    while(parent ! =null && ch == parent.left) {
                        ch = parent;
                        parent = parent.parent;
                    }
                    // returns the grandfather node
                    returnparent; }}else
                // If the key passed is equal to the current traversal node, return the current traversal node
                return p;

        }
        return null;
    }
Copy the code

GetHigherEntry method

// Returns a node that is only larger than the key passed in
final Entry<K,V> getHigherEntry(K key) {
    	// Get a copy of the root node
        Entry<K,V> p = root;
    	//while loop, p is null and exits
        while(p ! =null) {
            // Compare the incoming key with the current traversal node key
            int cmp = compare(key, p.key);
            if (cmp < 0) {
                // If the key passed in is smaller than the key currently traversed by the node
                if(p.left ! =null)
                    If the left child of the currently traversed node is not null, continue traversing to the left
                    // The current traversal node refers to the left child
                    p = p.left;
                else
                    // If the left child of the current traversal node is null
                    // Returns the current node
                    return p;
            } else {
                // If the key passed is greater than or equal to the current traversal node key
                if(p.right ! =null) {
                    // If the right child of the current traversal node is not null, continue traversal to the right
                    // The current traversal node points to the right child node
                    p = p.right;
                } else {
                    // If the right child of the current traversal node is null
                    // Get the parent of the current traversal node
                    Entry<K,V> parent = p.parent;
                    // Save a copy of the current traversal node
                    Entry<K,V> ch = p;
                    // the while loop iterates
                    // Look up until the parent node is the left child of the grandfather node
                    while(parent ! =null && ch == parent.right) {
                        ch = parent;
                        parent = parent.parent;
                    }
                    // returns the grandfather node
                    returnparent; }}}return null;
    }
Copy the code

getLowerEntry

// Returns a node that is only smaller than the key passed in
final Entry<K,V> getLowerEntry(K key) {
    	// Get a copy of the root node
        Entry<K,V> p = root;
   	    //while loop, p is null and exits
        while(p ! =null) {
            // Compare the incoming key with the current traversal node key
            int cmp = compare(key, p.key);
            if (cmp > 0) {
                // If the key passed is greater than the key currently traversed the node
                if(p.right ! =null)
                    // If the key currently traversed has a right child, continue traversing to the right
                    // Point the current traversal node to the right child node
                    p = p.right;
                else
                    // If the current traversal node does not have a right child, returns the current traversal node
                    return p;
            } else {
                // If the key passed is less than or equal to the current traversal node key
                if(p.left ! =null) {
                    If the left child of the current traversal node is not null, continue traversal to the left
                    // The current traversal node refers to the left child
                    p = p.left;
                } else {
                     // Get the parent of the current traversal node
                    Entry<K,V> parent = p.parent;
                    // A copy of the node currently traversed
                    Entry<K,V> ch = p;
                    // the while loop iterates
                    // Look up until the parent node is the right child of the grandfather node
                    while(parent ! =null && ch == parent.left) {
                        ch = parent;
                        parent = parent.parent;
                    }
                    // returns the grandfather node
                    returnparent; }}}return null;
    }
Copy the code

ContainsValue method

// Check whether the corresponding value exists
public boolean containsValue(Object value) {
    	// Use the for loop to find
    	//getFirstEntry gets the leftmost child node, which is the smallest node
    	Succeeded in obtaining the next node that is only larger than the current node
    	// The for loop is traversed from small to large by key
        for(Entry<K,V> e = getFirstEntry(); e ! =null; e = successor(e))
            // Use valEquals to compare values
            if (valEquals(value, e.value))
                // If it exists, return true
                return true;
    	// Does not exist, return false
        return false;
    }
Copy the code

GetFirstEntry method

// Get the first node with the smallest key, the leftmost child node
final Entry<K,V> getFirstEntry(a) {
    	// Get a copy of the root node
        Entry<K,V> p = root;
        if(p ! =null)
            // If the root is not null
            // Walk through the tree from the root node
            while(p.left ! =null)
                // Point the node to the left child node
                p = p.left;
    	// Return the node found all the way to the left
        return p;
    }
Copy the code

FirstEntry method

// Deep copy the first node
public Map.Entry<K,V> firstEntry(a) {
    	//getFirstEntry gets the first node with the smallest key, the leftmost child node
    	//exportEntry Returns a new SimpleImmutableEntry object
        return exportEntry(getFirstEntry());
    }
Copy the code

GetLastEntry method

// Get the rightmost node, the node with the largest key, that is, the rightmost child node
final Entry<K,V> getLastEntry(a) {
    	// Get a copy of the root node
        Entry<K,V> p = root;
        if(p ! =null)
            // If the root is not null
            // Walk through the tree from the root node
            while(p.right ! =null)
                // Point the node to the right child node
                p = p.right;
    	// Return the node found all the way to the right
        return p;
    }
Copy the code

LastEntry method

// Deep copy the last node
public Map.Entry<K,V> lastEntry(a) {
    	//getLastEntry gets the rightmost node with the largest key, that is, the rightmost child node
    	//exportEntry Returns a new SimpleImmutableEntry object
        return exportEntry(getLastEntry());
    }
Copy the code

Successor method

// Find the node whose key is only larger than the current node
static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
        if (t == null)
            // If the node is passed in as null, null is returned
            return null;
    	// Find the leftmost child of the right child
        else if(t.right ! =null) {
            // If the right child is not null
            // Save a copy of the right child node
            Entry<K,V> p = t.right;
            // Use the while loop to keep looking to the left
            while(p.left ! =null)
                p = p.left;
            // Returns the last node found
            return p;
        } else {
            // If the current node is the right node
            // The while loop keeps looking up until it finds that the parent is the left child, which is always smaller than the right
            Entry<K,V> p = t.parent;
            Entry<K,V> ch = t;
            while(p ! =null && ch == p.right) {
                ch = p;
                p = p.parent;
            }
            returnp; }}Copy the code

ValEquals method

// Compare whether two objects are equal
static final boolean valEquals(Object o1, Object o2) {
        return (o1==null ? o2==null : o1.equals(o2));
    }
Copy the code

Comparator method

// Get the comparator
public Comparator<? super K> comparator() {
        return comparator;
    }
Copy the code

FirstKey method

// Get the key of the first node (the leftmost child node)
public K firstKey(a) {
    	//getFirstEntry gets the first node
    	//key Obtains the key of the node
        return key(getFirstEntry());
    }
Copy the code

LastKey method

// Get the key of the last node (the rightmost child node)
public K lastKey(a) {
    	//getLastEntry gets the last node
    	//key Obtains the key of the node
        return key(getLastEntry());
    }
Copy the code

The key way to

// Get the key of the node
static <K> K key(Entry
       
         e)
       ,?> {
    	// If the node is null, an exception is thrown
        if (e==null)
            throw new NoSuchElementException();
        return e.key;
    }
Copy the code

KeyOrNull method

If the node is null, null is returned
static <K,V> K keyOrNull(TreeMap.Entry<K,V> e) {
        return (e == null)?null : e.key;
    }
Copy the code

PollFirstEntry method

// Get the first element and delete it
public Map.Entry<K,V> pollFirstEntry(a) {
    	//getFirstEntry gets the first node with the smallest key, the leftmost child node
        Entry<K,V> p = getFirstEntry();
    	// Generate a new Entry object according to p
        Map.Entry<K,V> result = exportEntry(p);
        if(p ! =null)
            // If p is not null, delete p
            deleteEntry(p);
    	// Returns the newly generated object
        return result;
    }
Copy the code

PollLastEntry method

// Get the last element and delete it
public Map.Entry<K,V> pollLastEntry(a) {
    	//getLastEntry gets the rightmost node with the largest key, that is, the rightmost child node
        Entry<K,V> p = getLastEntry();
    	// Generate a new Entry object according to p
        Map.Entry<K,V> result = exportEntry(p);
        if(p ! =null)
            // If p is not null, delete p
            deleteEntry(p);
    	// Returns the newly generated object
        return result;
    }
Copy the code

LowerEntry method

// Get a node that is only smaller than the key passed in and wrap it as a new object
public Map.Entry<K,V> lowerEntry(K key) {
    	//getLowerEntry gets the node that is only smaller than the key passed in
    	//exportEntry wraps a new object
        return exportEntry(getLowerEntry(key));
    }
Copy the code

LowerKey method

// Get the key of the node that is only smaller than the key passed in
public K lowerKey(K key) {
    	//getLowerEntry gets the node that is only smaller than the key passed in
    	//keyOrNull Obtains the key of the node
        return keyOrNull(getLowerEntry(key));
    }
Copy the code

FloorEntry method

// Returns a node that is no less than or equal to the key passed in, wrapped as a new object
public Map.Entry<K,V> floorEntry(K key) {
    	//getFloorEntry returns a node that is only less than or equal to the incoming key
    	//exportEntry wraps a new object
        return exportEntry(getFloorEntry(key));
    }
Copy the code

FloorKey method

// Returns the key of the node that is only less than or equal to the key passed in
public K floorKey(K key) {
    	//getFloorEntry returns a node that is only less than or equal to the incoming key
    	//keyOrNull Obtains the key of the node
        return keyOrNull(getFloorEntry(key));
    }
Copy the code

CeilingEntry method

// Returns a node that is only greater than or equal to the key passed in, wrapped as a new object
public Map.Entry<K,V> ceilingEntry(K key) {
    	//getCeilingEntry returns a node that is only greater than or equal to the passed key
    	//exportEntry wraps a new object
        return exportEntry(getCeilingEntry(key));
    }
Copy the code

CeilingKey method

// Returns the key of the node that is only greater than or equal to the key passed in
public K ceilingKey(K key) {
    	//getCeilingEntry returns a node that is only greater than or equal to the passed key
    	//keyOrNull Obtains the key of the node
        return keyOrNull(getCeilingEntry(key));
    }
Copy the code

HigherEntry method

// Returns a node just larger than the key passed in, wrapped as a new object
public Map.Entry<K,V> higherEntry(K key) {
    	//getHigherEntry returns a node that is only larger than the passed key
    	//exportEntry wraps a new object
        return exportEntry(getHigherEntry(key));
    }
Copy the code

HigherKey method

// Returns the key of the node that is only larger than the key passed in
public K higherKey(K key) {
    	//getHigherEntry returns a node that is only larger than the passed key
    	//keyOrNull Obtains the key of the node
        return keyOrNull(getHigherEntry(key));
    }
Copy the code

KeySet method

// Get the Set of all keys
public Set<K> keySet(a) {
    	// Call navigableKeySet
        return navigableKeySet();
    }
Copy the code

NavigableKeySet method

// Return a Set of keys
public NavigableSet<K> navigableKeySet(a) {
     	// Use the cache first
        KeySet<K> nks = navigableKeySet;
    	// If the cache is empty, recreate the KeySet object
    	// Note that KeySet is the inner class of TreeMap and can get all the properties of the TreeMap object
    	//KeySet is a subclass of NavigableSet that implements the NavigableSet interface
        return(nks ! =null)? nks : (navigableKeySet =new KeySet<>(this));
    }
Copy the code

DescendingKeySet method

/ / get descendingMap
public NavigableSet<K> descendingKeySet(a) {
        return descendingMap().navigableKeySet();
    }
Copy the code

DescendingMap method

/ / return descendingMap
public NavigableMap<K, V> descendingMap(a) {
        NavigableMap<K, V> km = descendingMap;
    	// If the cache is empty, recreate the DescendingSubMap object
    	// Note that DescendingSubMap is the inner class of TreeMap and retrieves all the attributes of the TreeMap object
        return(km ! =null)? km : (descendingMap =new DescendingSubMap<>(this.true.null.true.true.null.true));
    }
Copy the code

Values method

// Get the Colletion collection of all values
public Collection<V> values(a) {
    	// Use cache
        Collection<V> vs = values;
        if (vs == null) {
            // If the cache is empty, recreate the Values object
    	   // Note that Values is the inner class of TreeMap and can get all the attributes of the TreeMap object
            vs = new Values();
            values = vs;
        }
    	// Return the Colletion collection of value
        return vs;
    }
Copy the code

EntrySet method

// Get Entry objects for all key-value pairs
public Set<Map.Entry<K,V>> entrySet() {
    	// Use cache
        EntrySet es = entrySet;
    	// If the cache is empty, re-create the EntrySet object
    	// Note that EntrySet is an inner class of TreeMap and can get all the properties of the TreeMap object
        return(es ! =null)? es : (entrySet =new EntrySet());
    }
Copy the code

The replace method

@Override
	// To change the value of the node, compare the old value
    public boolean replace(K key, V oldValue, V newValue) {
        // Get the node by getEntry
        Entry<K,V> p = getEntry(key);
        if(p! =null && Objects.equals(oldValue, p.value)) {
            // If the node is not null and the value of the node is equal to the oldValue passed in
            // Assign the new value to the node
            p.value = newValue;
            // Successful modification, return true
            return true;
        }
        // Node does not exist, return false
        return false;
    }

@Override
	// Change the value of the node without comparing the old value
    public V replace(K key, V value) {
        // Get the node by getEntry
        Entry<K,V> p = getEntry(key);
        if(p! =null) {
            // If the node is not null
            // Get the old value of the node
            V oldValue = p.value;
            // Assign the new value to the node
            p.value = value;
            // Return the old value
            return oldValue;
        }
        // Node does not exist, return null
        return null;
    }
Copy the code

The forEach method

 @Override
    public void forEach(BiConsumer<? super K, ? super V> action) {
        // Check the validity of the parameter
        Objects.requireNonNull(action);
        // Get a copy of the modified statistics
        int expectedModCount = modCount;
        // The BiConsumer method is called on each node
        for(Entry<K, V> e = getFirstEntry(); e ! =null; e = successor(e)) {
            action.accept(e.key, e.value);
			// Throw an exception if some other thread changes during the traversal
            if(expectedModCount ! = modCount) {throw newConcurrentModificationException(); }}}Copy the code

ReplaceAll method

 @Override
    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
        // Check the validity of the parameter
        Objects.requireNonNull(function);
        // Get a copy of the modified statistics
        int expectedModCount = modCount;
		// The BiFunction method is called on each node
        for(Entry<K, V> e = getFirstEntry(); e ! =null; e = successor(e)) {
            e.value = function.apply(e.key, e.value);
			// Throw an exception if some other thread changes during the traversal
            if(expectedModCount ! = modCount) {throw newConcurrentModificationException(); }}}Copy the code

ExportEntry method

// Wrap the Entry object into a new object, deep copy?
static <K,V> Map.Entry<K,V> exportEntry(TreeMap.Entry<K,V> e) {
        return (e == null)?null :
            new AbstractMap.SimpleImmutableEntry<>(e);
    }
Copy the code

PutAll method

// Add elements to the Map object
public void putAll(Map<? extends K, ? extends V> map) {
    	// Get the size of the map object passed in
        int mapSize = map.size();
        if (size==0&& mapSize! =0 && map instanceof SortedMap) {
            // If map is SortedMap
            // Get the map comparatorComparator<? > c = ((SortedMap<? ,? >)map).comparator();if(c == comparator || (c ! =null && c.equals(comparator))) {
                // If the map comparator is equal to the current comparator
                // Add 1 to the modified statistics
                ++modCount;
                try {
                    // Use buildFromSorted to add elements
                    buildFromSorted(mapSize, map.entrySet().iterator(),
                                    null.null);
                } catch (java.io.IOException cannotHappen) {
                } catch (ClassNotFoundException cannotHappen) {
                }
                return; }}// If it is just a normal Map object, use the superclass method to add elements
        super.putAll(map);
    }
// The putAll method of the parent class
public void putAll(Map<? extends K, ? extends V> m) {
    	// Loop through the Map element to get the key-value pair and call the put method to add it
        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
            // Call the put method to add elements
            put(e.getKey(), e.getValue());
    }
Copy the code

Put method

// Add key-value pair elements
public V put(K key, V value) {
    	// Get a copy of the root node
        Entry<K,V> t = root;
        if (t == null) {
            // If root is null
            // Type check and null check. If the current comparator is NULL, objects for key must implement the Comparable interface
            compare(key, key); // type (and possibly null) check
		   // Create a new node based on the key and value, and use the new node as the root node
            root = new Entry<>(key, value, null);
            // Set the element count to 1
            size = 1;
            // Modify statistics by 1
            modCount++;
            / / returns null
            return null;
        }
    // The root node is not null
        int cmp;
    	//parent Inserts the parent node of the node
        Entry<K,V> parent;
        // split comparator and comparable paths
    	// Get the current comparator
        Comparator<? super K> cpr = comparator;
        if(cpr ! =null) {
            // If there is a comparator
            // The while loop iterates through the search
            do {
                // Point parent to the current node
                parent = t;
                // The key of the current node and the key passed in
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    // If the key passed in is smaller than the key of the current node, look left
                    // Point the current node to the left child node
                    t = t.left;
                else if (cmp > 0)
                    // If the key passed in is larger than the current node's key, look to the right
                    // Point the current node to the right child node
                    t = t.right;
                else
                    // If found, replace the value of the current node with the value passed in
                    return t.setValue(value);
            } while(t ! =null);
        }
    	// No comparator exists, use key comparator
        else {
            if (key == null)
                // If the passed key is empty, an exception is thrown
                throw new NullPointerException();
            / / to turn the key
            @SuppressWarnings("unchecked")
                Comparable<? super K> k = (Comparable<? super K>) key;
            // The while loop iterates through the search
            do {
                // Point parent to the current node
                parent = t;
                // Use key's built-in comparator for comparison
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    // If the key passed in is smaller than the key of the current node, look left
                    // Point the current node to the left child node
                    t = t.left;
                else if (cmp > 0)
                    // If the key passed in is larger than the current node's key, look to the right
                    // Point the current node to the right child node
                    t = t.right;
                else
                    // If found, replace the value of the current node with the value passed in
                    return t.setValue(value);
            } while(t ! =null);
        }
    	// Create a new node with the last node traversed as its parent
        Entry<K,V> e = new Entry<>(key, value, parent);
        if (cmp < 0)
            // If the inserted key is smaller than the parent's key, the new node is the left child node
            parent.left = e;
        else
            // If the inserted key is larger than the parent's key, the new node is the right child node
            parent.right = e;
    	// Balance after insertion
        fixAfterInsertion(e);
    	// The number of elements increases by 1
        size++;
    	// Modify statistics by 1
        modCount++;
    	/ / returns null
        return null;
    }
Copy the code

FixAfterInsertion method

// Balance the red-black tree after inserting the node
private void fixAfterInsertion(Entry<K,V> x) {
    	// Set the inserted node to red by default
        x.color = RED;
    	//while loop operation
    	// If the current node is not empty, the current node is not the root node, and the parent of the current node is a red node, the loop will continue
    	Exit the loop until the parent node is black or reaches the root node
        while(x ! =null&& x ! = root && x.parent.color == RED) {/ / * * * * * * * * * * * * * * * * if the parent node is grandfather left child node of the * * * * * * * * * * * * * * * * *
            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
                // Get the right node of the grandfather node, which is the right uncle node
                Entry<K,V> y = rightOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {
                    // If the right uncle node is red
                    // Color the parent node black
                    setColor(parentOf(x), BLACK);
                    // Color the right uncle node black
                    setColor(y, BLACK);
                    // Color the grandfather node to red
                    setColor(parentOf(parentOf(x)), RED);
                    // Point the current node to the grandfather node for the next loop
                    x = parentOf(parentOf(x));
                } else {
                    // If the right uncle node is black
                    if (x == rightOf(parentOf(x))) {
                        // If the current node is the right node of the parent node
                        // Point the current node to the parent node
                        x = parentOf(x);
                        // Rotate the node left based on the current node
                        rotateLeft(x);
                    }
                    // Color the parent node to black
                    setColor(parentOf(x), BLACK);
                    // Color the grandfather node into a red node
                    setColor(parentOf(parentOf(x)), RED);
                    // Based on the grandparent node, the node is right-handed
                    rotateRight(parentOf(parentOf(x)));
                    // Do the next loop
                }
                //*************************end************************
            } else {
                / / = = = = = = = = = = = = = = = = = = = = if the parent node is grandfather node's right child node = = = = = = = = = = = = = = = = = = = = = = = = = = = =
                // Get the left child of the grandfather node, i.e. the left uncle node
                Entry<K,V> y = leftOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {
                    // If the left uncle node is red
                    // Color the parent node to black
                    setColor(parentOf(x), BLACK);
                    // color the left uncle node to black
                    setColor(y, BLACK);
                    // Color the grandfather node into a red node
                    setColor(parentOf(parentOf(x)), RED);
                    // Point the current node to the grandparent node for the next loop
                    x = parentOf(parentOf(x));
                } else {
                    // If the left uncle node is black
                    if (x == leftOf(parentOf(x))) {
                        // If the current node is the left child node
                        // The current node points to the parent node
                        x = parentOf(x);
                        // Rotate the node right based on the current node
                        rotateRight(x);
                    }
                    // Color the parent node to black
                    setColor(parentOf(x), BLACK);
                    // Color the grandfather node into a red node
                    setColor(parentOf(parentOf(x)), RED);
                    // The node is left-handed based on the grandfather node
                    rotateLeft(parentOf(parentOf(x)));
                    // Do the next loop
                }
                //============================end=====================}}// Color the root node black
        root.color = BLACK;
    }
Copy the code

You can see from above that staining => sinistral => dextral or staining => dextral => sinistral

  • The inserted node defaults to red, which minimizes changes

  • If the uncle node is a red node

    • The parent node and the uncle node are dyed black, and the grandfather node is dyed red. Repeat the operation with the new node inserted as the grandfather node
  • If the uncle node is black

    • If the current node and the uncle node are both left child nodes

      • Points the current node to the parent node
      • The node is right-handed based on the current node
      • Color the parent node black
      • Color the grandfather node red
      • Based on the grandfather node, several points are left handed
      • And then the next cycle
    • If the current node is the right child, the uncle node is the left child

      • Color the parent node black
      • Color the grandfather node red
      • Based on the grandfather node, several points are left handed
      • And then the next cycle
    • If the current node and the uncle node are both right child nodes

      • Points the current node to the parent node
      • The current node is used as the base node for left-rotation
      • Color the parent node black
      • Color the grandfather node red
      • Based on the grandfather node, several points are left handed
      • And then the next cycle
    • If the current node is the left child, the uncle node is the right child

      • Color the parent node black
      • Color the grandfather node red
      • Based on the grandfather node, several points are left handed
      • And then the next cycle

RotateLeft method

/ / left
private void rotateLeft(Entry<K,V> p) {
        if(p ! =null) {
            // If the current node is not null
            // Get the right child of the current node
            Entry<K,V> r = p.right;
            // Point the right child of the current node to the left child of the right child of the current node
            p.right = r.left;
            if(r.left ! =null)
                // If the left child of the right child of the current node is not null
                // Point the parent of the right child of the current node to the left child of the current node
                r.left.parent = p;
            // The parent of the current node's right child points to the parent of the current node
            r.parent = p.parent;
            if (p.parent == null)
                // If the parent of the current node is null, the current node is the root node
                // Point the root node to the right child of the current node
                root = r;
            else if (p.parent.left == p)
                // If the current node is the left child of the parent node
                // Point the left child of the parent node to the right child of the current node
                p.parent.left = r;
            else
                // If the current node is the right child of the parent node
                // Point the right child of the parent node to the right child of the current node
                p.parent.right = r;
            // The left child of the right node points to the current node
            r.left = p;
            // The parent of the current node points to the right child nodep.parent = r; }}Copy the code

As you can see from the top, the essence of sinistral is

  • The current node P becomes the left child of pr, the right child of the current node P
  • The right child of the current node P becomes the left child PRL of the right child PR

RotateRight method

/ / right
private void rotateRight(Entry<K,V> p) {
        if(p ! =null) {
            // If the current node is not null
            // Get the left child of the current node
            Entry<K,V> l = p.left;
            // The left child of the current node points to the right child of the current node's left child
            p.left = l.right;
            // If the right child of the left child of the current node is not null
            // Point the parent of the left child of the current node to the current node
            if(l.right ! =null) l.right.parent = p;
            The parent of the left child of the current node points to the parent of the current node
            l.parent = p.parent;
            if (p.parent == null)
                // If the parent of the current node is null, the current node is the root node
                // Point the root node to the left child of the current node
                root = l;
            else if (p.parent.right == p)
                // If the current node is the right child of the parent node
                // Point the right child of the parent node to the left child of the current node
                p.parent.right = l;
            // If the current node is the left child of the parent node
            // Point the left child of the parent node to the left child of the current node
            else p.parent.left = l;
            // The right node of the current node's left child points to the current node
            l.right = p;
            // The parent of the current node points to the left child of the current nodep.parent = l; }}Copy the code

As you can see from the top, the essence of dextral rotation is

  • The current node P becomes the right child of pl, the left child of current node P
  • The left child of the current node P becomes the right child of the left child pl PLR

The remove method

// Remove the node corresponding to the key
public V remove(Object key) {
    	// Use getEntry to get the node corresponding to the key
        Entry<K,V> p = getEntry(key);
        if (p == null)
            // If no corresponding node exists, null is returned
            return null;
		// Get the value of the corresponding node
        V oldValue = p.value;
    	// Delete the node using deleteEntry
        deleteEntry(p);
    	// Return the old value
        return oldValue;
    }
Copy the code

Clear method

// Clear all elements
public void clear(a) {
    	// Modify statistics by 1
        modCount++;
    	// Set the number of elements to 0
        size = 0;
    	// Set the root node to null
        root = null;
    }
Copy the code

DeleteEntry method

// Delete a node
private void deleteEntry(Entry<K,V> p) {
    	// Modify statistics by 1
        modCount++;
    	// The number of elements is reduced by 1
        size--;
        // If strictly internal, copy successor's element to p and then make p
        // point to successor.
        if(p.left ! =null&& p.right ! =null) {
            // If both the left and right children of the p node exist
            // Find elements only greater than p
            Entry<K,V> s = successor(p);
            // Set p key and value to S key and value
            p.key = s.key;
            p.value = s.value;
            // point p to s
            p = s;
        } // p has 2 children

        // Start fixup at replacement node, if it exists.
    	// Set the node to be replaced. If the left child exists, use the left child, but not the right childEntry<K,V> replacement = (p.left ! =null ? p.left : p.right);

        if(replacement ! =null) {
            // If p has child nodes
            // Link replacement to parent
            / / * * * * * * * * * * * * * * * replacement parent node connected to the p * * * * * * * * * * * * * * * * * * * *
            replacement.parent = p.parent;
            if (p.parent == null)
                // If the parent of p is null, p is the root node
                // Set the root node to replacement
                root = replacement;
            else if (p == p.parent.left)
                // If p is the left child of the parent
                // Point the left child of the parent of the p node to replacement
                p.parent.left  = replacement;
            else
                 // If p is the right child of the parent
                // Point the right child of the parent of the p node to replacement
                p.parent.right = replacement;
		   //***************end********************
            // set all references to p to null
            p.left = p.right = p.parent = null;
            // Fix replacement
            if (p.color == BLACK)
                // If p is black
                // call fixAfterDeletion to balance the red-black tree
                fixAfterDeletion(replacement);
        } else if (p.parent == null) { // return if we are the only node.
            // If the parent of p is null, p is the root node
            // Set root to null
            root = null;
        } else { // No children. Use self as phantom replacement and unlink.
            //p has no child node
            if (p.color == BLACK)
                // If p is black
                // call fixAfterDeletion to balance the red-black tree
                fixAfterDeletion(p);
            if(p.parent ! =null) {
                // If the parent of p is not null
                if (p == p.parent.left)
                    // If p is the left child of the parent
                    // Set the left child of the parent node to null
                    p.parent.left = null;
                else if (p == p.parent.right)
                     // If p is the right child of the parent
                    // Set the right child of the parent node to null
                    p.parent.right = null;
                // set p's parent reference to null
                p.parent = null; }}}Copy the code

FixAfterDeletion method

// Balance the red-black tree after deleting the node
private void fixAfterDeletion(Entry<K,V> x) {
    	// If x is not the root node and x is black, continue the while loop
        while(x ! = root && colorOf(x) == BLACK) {if (x == leftOf(parentOf(x))) {
                // If the current node is the left child of the parent node
                // Get the right child of the parent node of the current node
                Entry<K,V> sib = rightOf(parentOf(x));
                if (colorOf(sib) == RED) {
                    // If the right sibling is red
                    // Color the right sibling node to black
                    setColor(sib, BLACK);
                    // Color the parent of the current node as a red node
                    setColor(parentOf(x), RED);
                    // The base node is left-handed based on the parent node
                    rotateLeft(parentOf(x));
                    // Reset the right sibling node
                    sib = rightOf(parentOf(x));
                }

                if (colorOf(leftOf(sib))  == BLACK &&
                    colorOf(rightOf(sib)) == BLACK) {
                    // If the children of the right sibling node are all black nodes
                    // Color the right sibling node to red
                    setColor(sib, RED);
                    // Point the current node to the parent node
                    x = parentOf(x);
                    // Do the next loop
                } else {
                    // The child of the right sibling has a red node
                    if (colorOf(rightOf(sib)) == BLACK) {
                        // If the right child of the right sibling is black (the left child is red)
                        // Color the left child of the right sibling to black
                        setColor(leftOf(sib), BLACK);
                        // Color the right sibling node to red
                        setColor(sib, RED);
                        // Rotate the base node with the right sibling node as the base node
                        rotateRight(sib);
                        // Reset the right sibling node
                        sib = rightOf(parentOf(x));
                    }
                    // Dye the color of the right sibling to the color of the parent
                    setColor(sib, colorOf(parentOf(x)));
                    // Color the parent node to black
                    setColor(parentOf(x), BLACK);
                    // Color the right child of the right sibling to black
                    setColor(rightOf(sib), BLACK);
                    // The base node is left-handed based on the parent node
                    rotateLeft(parentOf(x));
                    // Exit the while loop by pointing to rootx = root; }}else { // Symmetric Is symmetric with the following
                // If the current node is the right child of the parent node
                // Get the left child of the parent node of the current node
                Entry<K,V> sib = leftOf(parentOf(x));
                if (colorOf(sib) == RED) {
                    // If the left sibling is a red node
                    // Color the left sibling node to black
                    setColor(sib, BLACK);
                    // Color the parent node to red
                    setColor(parentOf(x), RED);
                    // Rotate the base node to the parent node
                    rotateRight(parentOf(x));
                    // Reset the left sibling node
                    sib = leftOf(parentOf(x));
                }

                if (colorOf(rightOf(sib)) == BLACK &&
                    colorOf(leftOf(sib)) == BLACK) {
                    // If the children of the left sibling are all black nodes
                    // Color the left sibling node to red
                    setColor(sib, RED);
                    // Point the current node to the parent node
                    x = parentOf(x);
                    // Do the next loop
                } else {
                    // The child of the left sibling node has red nodes
                    if (colorOf(leftOf(sib)) == BLACK) {
                        // If the left child of the left sibling is black (and the right child is red)
                        // Color the right child of the left sibling node to black
                        setColor(rightOf(sib), BLACK);
                        // Color the left sibling node to red
                        setColor(sib, RED);
                        // Perform left-rotation based on the left sibling node
                        rotateLeft(sib);
                        // Reset the left sibling node
                        sib = leftOf(parentOf(x));
                    }
                    // Color the left sibling node to the parent node
                    setColor(sib, colorOf(parentOf(x)));
                    // Color the parent node to black
                    setColor(parentOf(x), BLACK);
                    // Color the left child of the left sibling node to black
                    setColor(leftOf(sib), BLACK);
                    // Rotate the parent node as the base node
                    rotateRight(parentOf(x));
                    Exit the while loop by pointing the current node to the root nodex = root; }}}// Color the current node X to black
        setColor(x, BLACK);
    }
Copy the code

Summary:

  • The deletion balancing operation of red black trees is not well understood
  • Staining, left-handedness, right-handedness is the key to balance
  • The following data structure section will be illustrated in combination with the diagram, setting a flag first