查找队列中最新的n个记录

本文介绍了一种高效查找最新用户行为记录的方法,通过设计特定的数据结构和算法,实现了快速获取不同类型的最新n条记录,适用于大数据量场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

每天产生的记录入队列,查找最新的n个记录

问题描述:

/**
 * 表示一个用户行为,包含type,timestamp, info信息
 */
interface Action {
    public String getType();

    public long getTimestamp();

    public String getInfo();
}

/**
 * 表示一个用户的行为历史
 */
interface ActionHistory {
    public void addNewAction(Action action);

    public List<Action> getRecentActions(int n);

    public List<Action> getRecentActions(String type, int n);
}

给定两个接口,实现getRecentActions(int n)和getRecentActions(String type, int n)的两个方法,(不断产生的记录数据是按照时间戳Timestamp来排序,时间戳值越大表示数据越新。)分别查找:不区分类型和区分特定类型的查找最新的n条记录。

具体实现如下:

package cetcocean.alibaba;

import java.util.*;
import java.util.Map.Entry;

/**
 * @description:
 * @author: fangchangtan
 * @create: 2019-02-21 08:46
 */


public class SolutionTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        MyActionHistory myActionHistory = new MyActionHistory();
        //添加各种记录
        for (int i = 1; i < 50; i = i + 2) {
            MyAciton myAcitonTem = new MyAciton("myScan", i, String.valueOf(i));
            myActionHistory.addNewAction(myAcitonTem);
        }
        for (int i = 0; i < 50; i = i + 2) {
            MyAciton myAcitonTem = new MyAciton("myClick", i, String.valueOf(i));
            myActionHistory.addNewAction(myAcitonTem);
        }

        //...test 单个参数......
        List<Action> listSumActions = myActionHistory.getRecentActions(20);
        System.out.println("listSumActions.size(): " + listSumActions.size() + "   | 获得全部类别的前n项值:");
        for (int i = 0; i < listSumActions.size(); i++) {
            Action action = listSumActions.get(i);
            System.out.println("type:" + action.getType() + " ;Timestamp:" + action.getTimestamp() + ";");
        }

        //...test 两个参数......
        System.out.println("\n" + "---------------我是分割线--------------------------");
        List<Action> listTypeActions = myActionHistory.getRecentActions("myClick", 20);
        System.out.println("listTypeActions.size(): " + listTypeActions.size() + "   | 获得特定type类别的前n项值:");
        for (int i = 0; i < listTypeActions.size(); i++) {
            Action action = listTypeActions.get(i);
            System.out.println("type:" + action.getType() + " ;Timestamp:" + action.getTimestamp() + ";");
        }


    }


}

/**
 * 表示一个用户行为,包含type,timestamp, info信息
 */
interface Action {
    public String getType();

    public long getTimestamp();

    public String getInfo();
}

/**
 * 表示一个用户的行为历史
 */
interface ActionHistory {
    public void addNewAction(Action action);

    public List<Action> getRecentActions(int n);

    public List<Action> getRecentActions(String type, int n);
}

class MyAciton implements Action, Comparable<MyAciton> {
    private String type;
    private long timeStamp;
    private String info;

    public MyAciton(String type, long timeStamp, String info) {
        super();
        this.type = type;
        this.timeStamp = timeStamp;
        this.info = info;
    }

    public String getType() {
        return type;

    }

    public long getTimestamp() {
        return timeStamp;

    }

    public String getInfo() {
        return info;

    }

    @Override
    public int compareTo(MyAciton o) {//升序排序
        return this.getTimestamp() > o.getTimestamp() ? -1 : (this.getTimestamp() < o.getTimestamp() ? 1 : 0);
    }
}

class MyActionHistory implements ActionHistory {

    private static Map<String, List<Action>> mapAcitonRecord = new HashMap<>();

    @Override
    public void addNewAction(Action action) {
        // TODO Auto-generated method stub
        if (mapAcitonRecord.containsKey(action.getType())) {
            mapAcitonRecord.get(action.getType()).add(action);
        } else {
            ArrayList<Action> arrayList = new ArrayList<Action>();
            arrayList.add(action);
            mapAcitonRecord.put(action.getType(), arrayList);
        }
    }

    @Override
    public List<Action> getRecentActions(int n) {
        // TODO Auto-generated method stub
        return getSumTopN(n);
    }

    @Override
    public List<Action> getRecentActions(String type, int n) {
        return getTypeTopN(type, n);
    }


    public Map<String, List<Action>> getMapRecord() {
        // TODO Auto-generated method stub
        return mapAcitonRecord;
    }

    /**
     * 获得指定类型的最新n条记录
     *
     * @param type
     * @param n
     * @return
     */
    public List<Action> getTypeTopN(String type, int n) {
        ArrayList<Action> resultList = new ArrayList<>();
        if (mapAcitonRecord.containsKey(type)) {
            List<Action> list = mapAcitonRecord.get(type);
            int size = list.size();
            //防止非法参数传入
            if (n < 0 || n > size) {
                return resultList;
            }
            for (int i = size - 1; i >= size - n; i--) {
                resultList.add(list.get(i));
            }
            return resultList;
        }
        return resultList;
    }

    /**
     * 获取全部类型的最近topN记录
     *
     * @param n
     * @return
     */
    public List<Action> getSumTopN(int n) {
        //计数已经弹出第count个元素;保证增长的count==n
        int count = 0;
        Map<String, Integer> currIndexMap = new HashMap<>();
        ArrayList<Action> resultList = new ArrayList<>();

        //初始化保存各个类型的最有各个元素的下标,到currIndexMap
        for (Entry<String, List<Action>> entry : mapAcitonRecord.entrySet()) {
            String type = entry.getKey();
            List<Action> queueList = entry.getValue();
            int index = queueList.size() - 1;
            currIndexMap.put(type, index);
        }

        int typeSize = currIndexMap.size();//总的类型type数量
        PriorityQueue<Action> priorityQueue = new PriorityQueue<>();//其实际上是一个大顶锥的实现
        for (Entry<String, List<Action>> entry : mapAcitonRecord.entrySet()) {
            String type = entry.getKey();
            List<Action> queueList = entry.getValue();
            //将各个类型type的最后一个元素添加到priorityQueue,实际一共typeSize个
            priorityQueue.offer(queueList.get(currIndexMap.get(type)));
        }

        while (!priorityQueue.isEmpty()) {
            Action maxAction = priorityQueue.poll();//弹出最大的元素:最新时间戳
            resultList.add(maxAction);
            count++;
            if (count == n) {//计数增加到n时候,就停止循环
                break;
            }
            //更新到下一个下标:并将下一个目标的元素添加到大顶堆中
            String type = maxAction.getType();
            int nextIndex = currIndexMap.get(type) - 1;
            //单个队列中向前找的过程中,没有其他元素的值了:此时防止空指针出现,此时,该类型已经不存在了,直接将该type的指针记录清空
            if (nextIndex < 0) {
                currIndexMap.remove(type);
            }else {
                currIndexMap.put(type, nextIndex);
                priorityQueue.offer(mapAcitonRecord.get(type).get(nextIndex));
            }
            //最终所有type的元素都弹出,此时currIndexMap为空,表示没有元素可以加入优先级队列了.此时直接弹出所有的元素。
            if (currIndexMap.size() == 0) {
                while (!priorityQueue.isEmpty()) {
                    Action maxActionTem = priorityQueue.poll();//弹出最大的元素:最新时间戳
                    resultList.add(maxActionTem);
                    count++;
                }
                return resultList;
            }
        }
        return resultList;
    }


}

思考:1.时间复杂度+空间复杂度
时间复杂度:其中n表示topN中的前n大,k表示type类型数量
O(nklogk)
2.堆排序使用PriorityQueue是java原始提供的内部采用堆排序的方式实现返回最大值(大顶锥)。实现不停的插入元素,并返回最大值【注意重写其中的方法】。
3.该问题是一个【业务设计】+【算法结构】的问题。

### 如何在队列数据结构中查找特定元素 队列是一种遵循先进先出(FIFO, First In First Out)原则的数据结构。通常情况下,标准的队列操作仅支持从队首移除元素以及向队尾添加元素的操作。然而,在某些应用场景下可能需要对队列中的某个特定元素进行搜索或定位。 #### 方法一:通过迭代方式逐个比较 可以通过逐一访问队列中的每个元素并与目标值进行比较来完成搜索任务。由于队列本身不提供随机访问的功能,因此这种方法的时间复杂度为 O(n),其中 n 是队列中元素的数量[^1]。 以下是基于 Python 的代码示例: ```python from collections import deque def find_in_queue(queue, target): index = 0 temp_queue = deque() while queue: element = queue.popleft() # 移除并返回队首元素 if element == target: # 如果找到目标元素 return f"Element {target} found at position {index}" # 将当前元素暂存到临时队列中 temp_queue.append(element) index += 1 # 还原原始队列状态 while temp_queue: queue.append(temp_queue.popleft()) return "Element not found" # 测试代码 queue = deque([10, 20, 30, 40]) print(find_in_queue(queue, 30)) # 输出位置索引 ``` 上述方法会保留队列原有的顺序不变,并且能够准确定位目标元素的位置。 #### 方法二:利用辅助数据结构优化查询效率 如果频繁执行针对队列中某元素的查找操作,则可以考虑引入额外的数据结构(如哈希表),记录各元素及其对应于队列中的逻辑位置之间的映射关系。这样可以在接近常数时间复杂度内判断任意给定值是否存在于此队列之中[^2]。 不过需要注意的是,维护这种附加信息可能会增加程序运行时的空间开销以及更新成本。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值