Bidirectional linked list and LinkedHashMap

1. Advantages of two-way linked list over one-way linked list

For insert operation, both single linked list and double linked list have O(1) time complexity.
For deletion, we often see that the deletion time complexity of single linked list is O(1). In fact, this statement is not accurate. Because the deletion action is really O(1), just change the direction of the next pointer. However, before deleting, we need to find the precursor node. This operation is not O(1), but O(n).

Specifically, there are two situations for deleting data from linked lists:
1. Delete the node whose value is equal to a specific value.
2. Delete the node pointed to by the given pointer.

For the first case, no matter the single linked list or the double linked list, you need to traverse from the first node one by one, find the node whose value is equal to the given value, and then delete it. The time complexity is O(n).

In the second case, the node to be deleted has been found, but we need to find its predecessor node before deleting the node. For the single linked list, we have analyzed that the time complexity is O(n). Because the bidirectional linked list has two pointers, it can directly locate the precursor node in the case of O(1) time complexity.

Similarly, if you need to insert a node in front of the specified node, the time complexity of the two-way linked list is also O(n), while the single linked list is O(1).

2. Basic functions of LinkedHashMap

public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>

In JDK1.8, the LinkedHashMap declaration code is as above. It can be seen that LinkedHashMap inherits from HashMap and implements the Map interface.

The biggest difference between LinkedHashMap and HashMap is that HashMap is unordered. When we traverse the HashMap, it is unordered. However, we sometimes need an ordered Map, which can be inserted in the order of traversal, and the corresponding data structure is LinkedHashMap.

    /**
     * HashMap.Node subclass for normal LinkedHashMap entries.
     */
    static class Entry<K,V> extends HashMap.Node<K,V> {
        Entry<K,V> before, after;
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }

In JDK1.8, the internal class Entry in LinkedHashMap is defined. It is not difficult to see from the above code that compared with the Node class in the HashMap, the entries in the LinkedHashMap have two properties: before and after. Before and after actually maintain the two-way linked list in the LinkedHashMap.

The code of Node class in HashMap is as follows

    static 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;
        }
.......


The above pictures are from the Internet

Combined with the above code and diagram, focus on the analysis of the pointer inside

There is a next pointer in the Node, which is used to maintain the next attribute of the single linked list to solve the conflict key in the Hash bucket.
before and after pointers are used to maintain the two-way linked list, which is the two-way linked list for orderly access.

3.LinkedHashMap and HashMap traversal comparison

Wrote a short piece of code to briefly compare the traversal effect of LinkedHashMap and HashMap.

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapVisit {

    public static void visit() {
        LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
        map.put("b", 2);
        map.put("a", 1);
        map.put("d", 4);
        map.put("c", 3);
        for(Map.Entry<String, Integer> entry: map.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }

    public static void visit2() {
        Map<String, Integer> map = new HashMap<>();
        map.put("b", 2);
        map.put("a", 1);
        map.put("d", 4);
        map.put("c", 3);
        for(Map.Entry<String, Integer> entry: map.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }

    public static void main(String[] args) {
        visit();
        System.out.println();
        visit2();
    }
}

The result of running the above code:

b: 2
a: 1
d: 4
c: 3

a: 1
b: 2
c: 3
d: 4

It can be found from the above example that the LinkedHashMap traverses in the insertion order.

4.accessOrder parameter

The constructor of LinkedHashMap has an accessOrder attribute, which is false by default. The default order of LinkedHashMap is insertion order. If the accessOrder property is true, it implements access order. In the access sequence, the most recently accessed node will be the tail node and will be in the last position during traversal.

    public static void visit3() {
        LinkedHashMap<String, Integer> map = new LinkedHashMap<>(8, 0.75f,true);
        map.put("b", 2);
        map.put("a", 1);
        map.put("d", 4);
        map.put("c", 3);
        for(Map.Entry<String, Integer> entry: map.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
        int num = map.get("a");
        System.out.println();
        for(Map.Entry<String, Integer> entry: map.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }

The output of the above code is

b: 2
a: 1
d: 4
c: 3

b: 2
d: 4
c: 3
a: 1

Tags: data structure linked list

Posted on Sat, 18 Sep 2021 20:12:29 -0400 by veroaero