最优商品topk排名算法

简介: 最优商品topk排名算法

1 产生背景

topk是一个典型的业务场景,除了最优商品,包括推荐排名、积分排名所有涉及到排名前k的地方都是该算法的应用场合。

topk即得到一个集合后,筛选里面排名前k个数值。问题看似简单,但是里面的数据结构和算法体现着对解决方案性能的思索和深度挖掘。到底有几种方法,这些方案里蕴含的优化思路究竟是怎么样的?这节来讨论


2 解决方案

2.1 方案一:全局排序

全局排序,将集合整体排序后,取出最大的k个值就是需要的结果。

这种方案最糟糕,我只需要排名前k的元素,其他n-k个的顺序我并不关心,但是运算过程中,都得跟着做了没用的排序操作。


2.2 方案二:局部排序

局部排序,既然全局没必要,那我只取前k个,后面的就没必要理会了。

冒泡排序在排序算法中可以胜任该操作。我们按最大值往上冒泡为例,只要执行k次冒泡,那前k名就可以确定。但是这种方案依然不是最优办法。因为我们需要的是前k名,那至于这k个,谁大谁小并不需要关心,排序依然是个浪费。


2.3 方案三:最小堆

最小堆,既然没必要排序,那我们就不排序。

先将前k个元素形成一个最小堆,后面的n-k个元素依次与堆顶比较,小则丢弃大则替换堆顶并调整堆。直到n个全部完成为止。最小堆是topk的经典解决方案。


3 实现

下面就用最小堆实现topk

package com.oldlu.busi;
import java.util.Arrays;
public class Topk {
    //堆元素下沉,形成最小堆,序号从i开始
    static void down(int[] nodes,int i) {
        //顶点序号遍历,只要到1半即可,时间复杂度为O(log2n)
        while ( i << 1  <  nodes.length){
            //左子,为何左移1位?回顾一下二叉树序号
            int left = i<<1;
            //右子,左+1即可
            int right = left+1;
            //标记,指向 本节点,左、右子节点里最小的,一开始取i自己
            int flag = i;
            //判断左子是否小于本节点
            if (nodes[left] < nodes[i]){
                flag = left;
            }
            //判断右子
            if (right < nodes.length && nodes[flag] > nodes[right]){
                flag = right;
            }
            //两者中最小的与本节点不相等,则交换
            if (flag != i){
                int temp = nodes[i];
                nodes[i] = nodes[flag];
                nodes[flag] = temp;
                i = flag;
            }else {
                //否则相等,堆排序完成,退出循环即可
                break;
            }
        }
    }
    public static void main(String[] args) {
        //原始数据
        int[] src={3,6,2,7,4,8,1,9,2,5};
        //要取几个
        int k = 5;
        //堆,为啥是k+1?请注意,最小堆的0是无用的,序号从1开始
        int[] nodes = new int[k+1];
        //取前k个数,注意这里只是个二叉树,还不满足最小堆的要求
        for (int i = 0; i < k; i++) {
            nodes[i+1]=src[i];
        }
        System.out.println("before:"+Arrays.toString(nodes));
        //从最底的子树开始,堆顶下沉
        //这里才真正的形成最小堆
        for (int i = k>>1; i >= 1; i‐‐) {
down(nodes,i);
        }
        System.out.println("create:"+Arrays.toString(nodes));
        //把余下的n‐k个数,放到堆顶,依次下沉,topk堆算法的开始
        for (int i = src.length ‐ k;i<src.length;i++){
            if (nodes[1] < src[i]){
                nodes[1] = src[i];
                down(nodes,1);
            }
        }
        System.out.println("topk:"+Arrays.toString(nodes));
    }
}

4 结果分析

最终获取k个值成功,符合要求

中间不涉及排序问题


目录
相关文章
|
2月前
|
SQL 算法 Serverless
B端算法实践问题之使用concat_id算子获取用户最近点击的50个商品ID如何解决
B端算法实践问题之使用concat_id算子获取用户最近点击的50个商品ID如何解决
16 1
|
3月前
|
数据采集 机器学习/深度学习 算法
Python基于Apriori关联规则算法实现商品零售购物篮分析
Python基于Apriori关联规则算法实现商品零售购物篮分析
|
5月前
|
算法
【优选算法】——Leetcode——LCR 179. 查找总价格为目标值的两个商品
【优选算法】——Leetcode——LCR 179. 查找总价格为目标值的两个商品
|
5月前
|
存储 机器学习/深度学习 算法
数据结构与算法⑬(第四章_中_续二)堆解决Topk问题+堆的概念选择题
数据结构与算法⑬(第四章_中_续二)堆解决Topk问题+堆的概念选择题
46 3
|
4月前
|
搜索推荐 算法 前端开发
计算机Java项目|基于协同过滤算法的体育商品推荐系统
计算机Java项目|基于协同过滤算法的体育商品推荐系统
|
5月前
|
算法 C++
算法--topk问题
该文介绍了TopK问题的两种解决方案:大小根堆和快排分割。使用大根堆可以找到前K小的元素,小根堆则用于找到前K大的元素。示例代码展示了如何用C++实现这两个方法。快排分割通过不断调整数组结构,找到第K大或第K小的元素。文章提供了相应的代码示例及输出结果。
30 0
|
5月前
|
移动开发 算法 数据可视化
数据分享|Spss Modeler关联规则Apriori模型、Carma算法分析超市顾客购买商品数据挖掘实例
数据分享|Spss Modeler关联规则Apriori模型、Carma算法分析超市顾客购买商品数据挖掘实例
|
5月前
|
搜索推荐 算法
基于用户的协同过滤算法实现商品推荐
基于用户的协同过滤算法实现商品推荐
72 2
|
10月前
|
搜索推荐 算法 前端开发
商品购物管理与推荐系统Python+Django网页界面+协同过滤推荐算法
商品购物管理与推荐系统Python+Django网页界面+协同过滤推荐算法
109 0
|
5月前
|
算法
堆排序+TopK问题——“数据结构与算法”
堆排序+TopK问题——“数据结构与算法”
下一篇
无影云桌面