## preface

• I have written an article about LRU elimination algorithm before. LRU algorithm records that the idea of LRU algorithm is to eliminate the least recently used elements. When an element is not accessed for a period of time, it is highly likely that it will not be accessed for a period of time afterwards, and then it will be eliminated when the data pool is full.
• This article intends to write about the idea and implementation of LFU algorithm. The idea of LFU algorithm is to eliminate the element with the lowest frequency of recent time use. If there are multiple elements with the lowest frequency of use, then the element with the shortest time in the data pool will be eliminated.
• Compared with LFU algorithm, LRU algorithm uses time dimension to eliminate data based on elements, while LFU algorithm uses frequency dimension to eliminate data. Generally speaking, THE LFU elimination algorithm is better than the LRU elimination algorithm, as long as it is more suitable for the business scenario.
• Before a little lazy so I did not write lRU algorithm code implementation -_-. This time, the lFU algorithm code implementation first out, later have the opportunity to find a time to write the LRU algorithm code implementation, anti-proper understanding of the principle of the realization of the idea is actually quite simple.

## O(N) implementation of LFU code implementation

• First, according to the IDEA of LFU algorithm, the linked list is directly thought of:
``````
/** * LFU algorithm list implementation **@author zrh
* @date2021/03/28 * /
public class LfuTest {

/** * Size of linked list datapool */
private final static Integer size = 3;

public static void main(String[] args) {
// Simulate the inserted element
String[] data = {"a"."b"."c"."a"."a"."a"."a"."b"."c"."d"};
for (String param : data) {
// Perform an insert
test(list, param);
System.out.println("Add element [" + param + "】, result:"+ list); }}private static void test(LinkedList<LfuNode> list, String param) {
// Check whether there are elements in the list
if(! list.isEmpty()) { Iterator<LfuNode> iterator = list.iterator();while (iterator.hasNext()) {
LfuNode next = iterator.next();
// Determine if there is an element in the list that is currently inserted
if (next.value.equals(param)) {
// Data usage frequency +1, and remove data
next.fre += 1;
iterator.remove();
// Loop the data to compare the FRE and reinsert the data into the list where appropriate
for (int i = 0; i < list.size(); i++) {
if (i == list.size() - 1) {
// Add the last bit to the end of the list
return;
} else if (list.get(i).fre <= next.fre
&& list.get(i + 1).fre > next.fre) {
// Insert next at I +1 if the frequency of the I bit element data is less than or equal to the frequency of the current Next, and the frequency of the current Next is less than the frequency of the I +1 bit element data.
// If the elements have the same frequency, put the elements as far to the right as possible, because deleting an element directly removes the leftmost element (the list header element).
return; }}return; }}// If there is data in the list, and new data is inserted, and the list size has reached the maximum, delete the list head node element directly.
if(list.size() == size) { list.removeFirst(); }}// If the list has no elements, add them directly to the list header node
}

@Data
static class LfuNode {
/ / data
private String value;
// Data usage frequency
private Integer fre;

public LfuNode(String value) {
this.value = value;
this.fre = 1; }}} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- running after printing results: add elements [a], result: [LfuTest. LfuNode (value = a, fre =1Lfunode.lfunode (value=b, fre=1), LfuTest.LfuNode(value=a, fre=1[lfutest.lFUNode (value=c, fre=1), LfuTest.LfuNode(value=b, fre=1), LfuTest.LfuNode(value=a, fre=1LfuNode(value=c, fre=1), LfuTest.LfuNode(value=b, fre=1), LfuTest.LfuNode(value=a, fre=2LfuNode(value=c, fre=1), LfuTest.LfuNode(value=b, fre=1), LfuTest.LfuNode(value=a, fre=3LfuNode(value=c, fre=1), LfuTest.LfuNode(value=b, fre=1), LfuTest.LfuNode(value=a, fre=4LfuNode(value=c, fre=1), LfuTest.LfuNode(value=b, fre=1), LfuTest.LfuNode(value=a, fre=5[lfutest.lFUNode (value=c, fre=1), LfuTest.LfuNode(value=b, fre=2), LfuTest.LfuNode(value=a, fre=5LfuNode(value=b, fre=2), LfuTest.LfuNode(value=c, fre=2), LfuTest.LfuNode(value=a, fre=5LfuNode(value=d, fre=1), LfuTest.LfuNode(value=c, fre=2), LfuTest.LfuNode(value=a, fre=5)]
Copy the code``````
• The last three elements in the datapool (linked list) are [D, C, a]. In this case, if lRU algorithm is used to eliminate data, the result after element insertion is [b, C, d].

## O(1) implementation of LFU code implementation

• Optimize the time complexity to O(1) with the quick lookup of HashMap and the quick add and remove of elements of LinkedHashSet.
``````/** * LFU algorithm implementation 2: optimization implementation **@Author: ZRH
* @Date: 2021/3/29 * /
public class LfuCache<K.V> {

/** * Data pool capacity, minimum frequency */
private static Integer capacity;
private static Integer minFre;
private Map<K, LfuNode<K, V>> map1;

/** * constructor - initialization parameter **@param capacity
*/
public LfuCache (Integer capacity) {
this.capacity = capacity;
this.minFre = 1;
this.map1 = new HashMap<>();
this.map2 = new HashMap<>();
}

/** * Add element method **@param k
* @param v
*/
private void add (K k, V v) {
if (map1.isEmpty()) {
LfuNode node = new LfuNode(k, v);
map1.put(k, node);
map2.put(node.fre, set);
return;
}

LfuNode<K, V> node;
// The current key is in the data cache pool
if((node = map1.get(k)) ! =null) {
// Remove a node from the set where the node frequency is key
set1.remove(node);
if (set1.isEmpty()) {
// Clear the empty collection
map2.remove(node.fre);
}
// Use frequency +1
node.fre += 1;
if (null == set2) {
}
// Add the current node to the new set with frequency key
map2.put(node.fre, set2);
// Maintain the minimum usage frequency parameter
minFre = map2.keySet().stream().min(Integer::compare).get();
return;
}
// Create a new node object based on K V
node = new LfuNode(k, v);
// The current datapool capacity is full, and the least frequently used elements will be eliminated.
// If the least frequently used element in the set has multiple elements, the oldest element will be eliminated.
if (map1.size() == capacity) {
// Fetch the set of keys based on the minimum frequency of use
// Delete the first element (which represents the oldest element) according to the insertion order of the LinkedHashSet
final Iterator<LfuNode<K, V>> iterator = set.iterator();
LfuNode<K, V> oldNode = null;
while (iterator.hasNext()) {
oldNode = iterator.next();
iterator.remove();
break;
}
// Eliminate elements in MAP1
map1.remove(oldNode.key);
}
// Insert new element into map1, map2 set
map1.put(k, node);
if (set1 == null) {
}
map2.put(node.fre, set1);
// Maintain the minimum usage frequency parameter
minFre = node.fre;
return;
}

@Data
static class LfuNode<K.V> {
/**
* K键 V值 fre使用频率
*/
private K key;
private V value;
private Integer fre;

public LfuNode (K key, V value) {
this.key = key;
this.value = value;
this.fre = 1; }}public static void main (String[] args) {
String[] data = {"a"."b"."c"."a"."a"."a"."a"."b"."c"."d"};
LfuCache cache = new LfuCache(3);
for (String param : data) {
System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
System.out.println(Insert element [" + param + ", minimum element frequency =" + minFre);
System.out.println(" map1 = " + JSON.toJSONString(cache.map1));
System.out.println(" map2 = "+ JSON.toJSONString(cache.map2)); }}} running after printing results: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 【 a 】 insert element, element = minimum frequency1
map1 = {"a": {"fre":1."key":"a"."value":"a"}}
map2 = {1: [{"fre":1."key":"a"."value":"a"}]} ------------------------- Insert element [b], element minimum frequency =1
map1 = {"a": {"fre":1."key":"a"."value":"a"},"b": {"fre":1."key":"b"."value":"b"}}
map2 = {1: [{"fre":1."key":"a"."value":"a"}, {"fre":1."key":"b"."value":"b"}]} ------------------------- Insert element [c], element minimum frequency =1
map1 = {"a": {"fre":1."key":"a"."value":"a"},"b": {"fre":1."key":"b"."value":"b"},"c": {"fre":1."key":"c"."value":"c"}}
map2 = {1: [{"fre":1."key":"a"."value":"a"}, {"fre":1."key":"b"."value":"b"}, {"fre":1."key":"c"."value":"c"}]} ------------------------- Insert element [a], element minimum frequency =1
map1 = {"a": {"fre":2."key":"a"."value":"a"},"b": {"fre":1."key":"b"."value":"b"},"c": {"fre":1."key":"c"."value":"c"}}
map2 = {1: [{"fre":1."key":"b"."value":"b"}, {"fre":1."key":"c"."value":"c"}].2: [{"fre":2."key":"a"."value":"a"}]} ------------------------- Insert element [a], element minimum frequency =1
map1 = {"a": {"fre":3."key":"a"."value":"a"},"b": {"fre":1."key":"b"."value":"b"},"c": {"fre":1."key":"c"."value":"c"}}
map2 = {1: [{"fre":1."key":"b"."value":"b"}, {"fre":1."key":"c"."value":"c"}].3: [{"fre":3."key":"a"."value":"a"}]} ------------------------- Insert element [a], element minimum frequency =1
map1 = {"a": {"fre":4."key":"a"."value":"a"},"b": {"fre":1."key":"b"."value":"b"},"c": {"fre":1."key":"c"."value":"c"}}
map2 = {1: [{"fre":1."key":"b"."value":"b"}, {"fre":1."key":"c"."value":"c"}].4: [{"fre":4."key":"a"."value":"a"}]} ------------------------- Insert element [a], element minimum frequency =1
map1 = {"a": {"fre":5."key":"a"."value":"a"},"b": {"fre":1."key":"b"."value":"b"},"c": {"fre":1."key":"c"."value":"c"}}
map2 = {1: [{"fre":1."key":"b"."value":"b"}, {"fre":1."key":"c"."value":"c"}].5: [{"fre":5."key":"a"."value":"a"}]} ------------------------- Insert element [b], element minimum frequency =1
map1 = {"a": {"fre":5."key":"a"."value":"a"},"b": {"fre":2."key":"b"."value":"b"},"c": {"fre":1."key":"c"."value":"c"}}
map2 = {1: [{"fre":1."key":"c"."value":"c"}].2: [{"fre":2."key":"b"."value":"b"}].5: [{"fre":5."key":"a"."value":"a"}]} ------------------------- Insert element [c], element minimum frequency =2
map1 = {"a": {"fre":5."key":"a"."value":"a"},"b": {"fre":2."key":"b"."value":"b"},"c": {"fre":2."key":"c"."value":"c"}}
map2 = {2: [{"fre":2."key":"b"."value":"b"}, {"fre":2."key":"c"."value":"c"}].5: [{"fre":5."key":"a"."value":"a"}]} ------------------------- Insert element [d], element minimum frequency =1
map1 = {"a": {"fre":5."key":"a"."value":"a"},"c": {"fre":2."key":"c"."value":"c"},"d": {"fre":1."key":"d"."value":"d"}}
map2 = {1: [{"fre":1."key":"d"."value":"d"}].2: [{"fre":2."key":"c"."value":"c"}].5: [{"fre":5."key":"a"."value":"a"}}]Copy the code``````

### The last

• The LFU algorithm is supported in the Redis memory weeding strategy and the Dubbo cache weeding strategy.
• If there are any errors in the above code, you are welcome to point out and I will correct it -_-
• For details about algorithm implementation, see the LFU algorithm
• Study with an open mind and make progress together