热度排行榜实现方案(java基于LRU算法的实现方式)

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

背景:

突发奇想在我的小平台上添加一个文件下载排行榜,类似于百度的热搜(如下图)。

image.png

方案

使用LRU算法实现,该方案就是在内存中维护一个双向链表。将页面准备展示的排行榜的最小名次(例如:上图中的15就是最小名词)作为链表的固定长度,将前台每次下载的文件名称都插入到链表的头部,如果插入的内容超过链表的长度,则把链表的尾节点删除,用以保证链表的长度不变,这样就自然的形成了一个排行榜,最新的下载永远在前边。

代码实现: 1、Node节点

package com.cz.commons.rank;

/**
 * 节点(该节点用于后续构建双向链表)
 * @program: PostGirl-panent
 * @description: Node
 * @author: Cheng Zhi
 * @create: 2021-09-23 16:28
 **/
public class Node {

    public Object key, val;
    public Node next; // 下一个节点
    public Node prev; // 当前节点
    public Node(Object k, Object v) {
        this.key = k;
        this.val = v;
    }

}
复制代码

Rank排行榜

package com.cz.commons.rank;

import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 构造排行榜列表,使用双向链表实现
 * @program: PostGirl-panent
 * @description: Rank
 * @author: Cheng Zhi
 * @create: 2021-09-23 16:30
 **/
@Component
public class Rank<K,V> {
    private int capcity = 10; // 总容量
    private int currentSize = 0; // 当前容量
    private Node firstNode; // 头节点
    private Node lastNode; // 尾节点
    private Map<K,Node> caches = new HashMap<K,Node>(10); // 榜单

    /**
     * 新增节点(先判断榜单上是否存在该节点,如果存在,则排名提升到第一,如果不存在,插入到链表头,同时删除尾节点)
     * @param key
     * @param value
     */
    public void add(K key, V value) {

        Node node = caches.get(key);
        if (node == null) {
            // 新增节点
            if (caches.size() >= capcity) {

                // 移除最后一个节点
                caches.remove(lastNode.key);
                // 组织移除后的节点关系
                lastNode = lastNode.prev;
                lastNode.next = null;
            }

            // 插入新节点
            node = new Node(key, value);

            // 组织插入后的节点关系
            node.next = firstNode;

            if (node.next == null) {
                lastNode = node;
            } else {
                node.next.prev = node;
            }
            firstNode = node;
            currentSize ++;
        } else {

            // 插入已存在的节点
            if (node == firstNode) {
                return;
            }
            node.val = value;

            if (node.prev != null) {
                node.prev.next = node.next;
            }
            if (node.next != null) {
                node.next.prev = node.prev;
            }
            node.next = firstNode;
            node.next.prev = node;
            firstNode = node;
        }
        caches.put(key, node);
    }

    /**
     * 移除节点(先判断榜单上是否存在该节点,如果存在则删除同时改变该节点的前驱和后继)
     * @param key
     */
    public void remove(K key) {

        Node node = caches.get(key);

        if (node == null) {
            return;
        }

        node.prev.next = node.next;
        if (node.next != null) {
            node.next.prev = node.prev;
        }

        caches.remove(key);
    }

    /**
     * 获取榜单
     */
    public List<String> getRank() {

        List<String> lists = new ArrayList<String>();
        Node node = firstNode;
        while (node != null) {
            lists.add((String) node.val);
            node = node.next;
        }

        return lists;
    }
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        Node node = firstNode;
        while (node != null) {
            sb.append(String.format("%s:%s ", node.key, node.val));
            node = node.next;
        }
        return sb.toString();
    }
}
复制代码

效果

在这里插入图片描述

猜你喜欢

转载自juejin.im/post/7102023823645474852