TOPK算法 - 线性遍历

作者: 半亩房顶 | 来源:发表于2019-03-04 16:20 被阅读7次

应用场景

在大量数据当中,寻找最大的几个值,完整排序可能会造成极大的不必要开销,所以TOPK算法很有掌握的必要

思路

今天主要是整理了小顶堆TOPK算法。常规快排作为对比项

代码

常规快排:

这个快排写法相较于常见的交换位置的写法相比,更加舒服点

<?php

    //为了测试运行内存调大一点
    ini_set('memory_limit', '2024M');
    ini_set("max_execution_time", "1200");


    //实现一个快速排序函数
    function quick_sort(array $array){
        $length = count($array);
        $left_array = array();
        $right_array = array();
        if($length <= 1){
            return $array;
        }
        $key = $array[0];
        for($i=1;$i<$length;$i++){
            if($array[$i] > $key){
                $left_array[] = $array[$i];
            }else{
                $right_array[] = $array[$i];
            }
        }
        $left_array = quick_sort($left_array);
        $right_array = quick_sort($right_array);
        return array_merge($left_array,array($key),$right_array);
    }

    //构造500w不重复数
    for($i=0;$i<5000000;$i++){
        $numArr[] = $i; 
    }
    //打乱它们
    shuffle($numArr);

    //现在我们从里面找到top10最大的数
    $start = microtime(true);
    var_dump(array_slice(quick_sort($numArr),0,10));
    $end = microtime(true);
    echo '耗时' . round($end - $start, 3) . '秒';

结果如图:


小顶堆:

假如N为10,则先取出10个数,构建小顶堆,然后线性遍历一遍其余数据,大于堆顶的替换堆顶元素并重新调整一遍小顶堆

<?php

    //为了测试运行内存调大一点
    ini_set('memory_limit', '2024M');

    //生成小顶堆函数
    function Heap(&$arr,$idx){
        $left  = ($idx << 1) + 1;
        $right = ($idx << 1) + 2;

        if (!$arr[$left]){
            return;
        }

        if($arr[$right] && $arr[$right] < $arr[$left]){
            $l = $right;
        }else{
            $l = $left;
        }

        if ($arr[$idx] > $arr[$l]){
             $tmp = $arr[$idx]; 
             $arr[$idx] = $arr[$l];
             $arr[$l] = $tmp;
             Heap($arr,$l);
        }
    }

    //这里为了保证跟上面一致,也构造500w不重复数
    /*
      当然这个数据集并不一定全放在内存,也可以在
      文件里面,因为我们并不是全部加载到内存去进
      行排序
    */
    for($i=0;$i<5000000;$i++){
        $numArr[] = $i;    
    }
    //打乱它们
    shuffle($numArr);

    $start = microtime(true);
    //先取出10个到数组
    $topArr = array_slice($numArr,0,10);

    //获取最后一个有子节点的索引位置
    //因为在构造小顶堆的时候是从最后一个有左或右节点的位置
    //开始从下往上不断的进行移动构造(具体可看上面的图去理解)
    $idx = floor(count($topArr) / 2) - 1;

    //生成小顶堆
    for($i=$idx;$i>=0;$i--){
        Heap($topArr,$i);
    }

    //这里可以看到,就是开始遍历剩下的所有元素
    for($i = count($topArr); $i < count($numArr); $i++){
        //每遍历一个则跟堆顶元素进行比较大小
        if ($numArr[$i] > $topArr[0]){
            //如果大于堆顶元素则替换
            $topArr[0] = $numArr[$i];
            /*
              重新调用生成小顶堆函数进行维护,只不过这次是从堆顶
              的索引位置开始自上往下进行维护,因为我们只是把堆顶
              的元素给替换掉了而其余的还是按照根节点小于左右节点
              的顺序摆放这也就是我们上面说的,只是相对调整下,并
              不是全部调整一遍
            */
            Heap($topArr,0);
        }
    }
    var_dump($topArr);
    $end = microtime(true);
    echo '耗时' . round($end - $start, 3) . '秒';

结果如图:


总结

其实最关键的思路在于线性遍历,先将小范围的数据排序,再线性遍历其它数据,这个排序算法的选择并不一定是堆排序。
其实对比并不严谨,不过主要是为了说明常规排序和线性遍历思路的区别。

相关文章

  • TOPK算法 - 线性遍历

    应用场景 在大量数据当中,寻找最大的几个值,完整排序可能会造成极大的不必要开销,所以TOPK算法很有掌握的必要 思...

  • Java快速排序

    线性查找 1.定义: 线性查找是按照序列原有顺序对数组进行遍历比较查询的基本查找算法 2.原理: 通过遍历数组来寻...

  • 索引算法

    索引算法介绍 线性查找 线性查找就是最简单的查找算法,在一个数组或者链表从头到尾遍历查找,时间复杂度是o(n) 二...

  • topK算法问题

    问题描述:有 N (N>1000000)个数,求出其中的前K个最小的数(又被称作topK问题)。 这类问题似乎是备...

  • TopK 算法的多种实现

    我是前端西瓜哥,今天来整下 TopK 算法。 TopK,即求数组的最小(或最大)的 k 个数,且不要求这些数要排序...

  • 线性搜索算法 Go

    说明 线性搜索是指从数组0下标开始,依次序搜索对比的搜索方式。 代码 代码说明 面向算法:线性遍历数组,通过闭包传...

  • C#实现基于权重的随机算法

    一、线性扫描 最简单常用的算法,获取随机值,直接遍历。 二、预处理 首先对权重进行处理,填充PrepareAdRe...

  • (12)海量数据处理

    海量数据处理主要涉及分治算法,其中包含排序、求TopK、以及查找重复的问题 (1)Top K 算法思路:(1) 局...

  • 排序算法

    一、排序算法总结 排序算法题目 排序算法快速排序堆排序归并排序 应用最小K个数(TopK问题)215.数组中的第K...

  • 数据结构课程 第八周 遍历二叉树

    存储结构为二叉链表 遍历 先序遍历递归算法 中序遍历递归算法 后序遍历递归算法 总结 时间O(n) 空间(O(n)...

网友评论

    本文标题:TOPK算法 - 线性遍历

    本文链接:https://www.haomeiwen.com/subject/smsiuqtx.html