关于堆排序和topK算法的PHP实现
问题描述
topK算法,简而言之,就是求n个数据里的前m大个数据,一般而言,m<<n,也就是说,n可能有几千万,而m只是10或者20这样的两位数。
思路
最简单的思路,当然是使用要先对这n个数据进行排序,因为只有排序以后,才能按照顺序来找出排在前面的,或者排在后面的数据。
假如说我们用快拍,那么时间复杂度是O(nlogn),但是仔细看题目,会发现实际上不要要将所有的数据就进行排序,因为我们找的是前m个数据,所以对所有数据排序实际上有些浪费了。所以可以想到,只维护一个大小为m的数组,然后扫一遍原来的数组n,只将大于数组m里的最小值的数据插入到m数组里,并且重新调整m数组的顺序。
如果使用朴素的方法对m数组进行调整,那么时间复杂度将会是O(n*m),这显然不是最优的结果。对于维护的数组m,我们可以通过维护一个堆结构,来达到每次排序O(logm)的时间复杂度,这样topK算法,总体的复杂度也就变成了O(nlogm)。
关于堆
二叉堆是完全二叉树或者是近似完全二叉树。
二叉堆满足二个特性:
1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。下图展示一个最小堆:一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。
PHP实现的堆
class Heap { protected $listSize; protected $tree; public function __construct($list) { $this->listSize = count($list); $i = 1; foreach ($list as $li) { $this->tree[$i++] = $li; } unset($list); $this->initHeap(); } public function getSortedResult() { $this->initHeap(); $this->sortHeap(); return $this->tree; } public function getHeapResult() { return $this->tree; } public function getTopNode() { return $this->tree[1]; } public function setTopNode($value) { $this->tree[1] = $value; $this->adjustHeap(1, $this->listSize); } public function sortHeap() { for ($end = $this->listSize; $end > 1; $end--) { $this->swap($this->tree[1], $this->tree[$end]); $this->adjustHeap(1, $end - 1); } } private function initHeap() { for ($start=floor($len / 2); $start >= 1; $start--) { $this->adjustHeap($start, $this->listSize); } } private function adjustHeap($start, $len) { $tmp = $start; // 临时变量,用于保存最大值或者最小值的下标索引 $lChildInx = $start * 2; $rChildInx = $lChildInx + 1; if ($start <= floor($len / 2)) { if($lChildInx <= $len && $this->tree[$lChildInx] < $this->tree[$tmp]) { $tmp = $lChildInx; } if($rChildInx <= $len && $this->tree[$rChildInx] < $this->tree[$tmp]) { $tmp = $rChildInx; } if ($tmp != $start) { $this->swap($this->tree[$tmp], $this->tree[$start]); $this->adjustHeap($tmp, $len); } } } private function swap(&$a, &$b) { $temp = $a; $a = $b; $b = $temp; } }
topK
include 'Heap.class.php'; $list = range(1,10000); shuffle($list); $k = 15; $initHeapNodes = array_slice($list, 0, $k); $heap = new Heap($initHeapNodes); $n = count($list); for ($i=$k; $i<$n; $i++) { if ($list[$i] > $heap->getTopNode()) { $heap->setTopNode($list[$i]); } } print_r($heap->getSortedResult());
关于堆排序和topK算法的PHP实现的更多相关文章
- java TopK算法
现有一亿个数据,要求从其中找出最小的一万个数,希望所需的时间和空间最小,也就是所谓的topK问题 TopK问题就是从海量的数据中取最大(或最小的)的K个数. TopK问题其实是有线性时间复杂度的解的, ...
- (转)基于快速排序的TOPK算法
基于快速排序的TOPK算法 转自:http://blog.csdn.net/fanzitao/article/details/7617223 思想: 类似于快速排序,首先选择一个划分元,如果这个划分元 ...
- [数据结构]——堆(Heap)、堆排序和TopK
堆(heap),是一种特殊的数据结构.之所以特殊,因为堆的形象化是一个棵完全二叉树,并且满足任意节点始终不大于(或者不小于)左右子节点(有别于二叉搜索树Binary Search Tree).其中,前 ...
- 堆排序与优先队列——算法导论(7)
1. 预备知识 (1) 基本概念 如图,(二叉)堆是一个数组,它可以被看成一个近似的完全二叉树.树中的每一个结点对应数组中的一个元素.除了最底层外,该树是完全充满的,而且从左向右填充.堆的数组 ...
- topk算法
方法一 堆排序 自建堆 heapMax方法,从上至下调整堆 pop时,可以使用自上而下调整堆,调用heapMax(arr,0,sz-1); push时,需要自下到上调整即 从上到下调整: void h ...
- topK 算法
搜索引擎热门查询统计 题目描述: 搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节. 假设目前有一千万个记录(这些查询串的重复度比较高,虽然 ...
- python堆排序实现TOPK问题
# 构建小顶堆跳转def sift(li, low, higt): tmp = li[low] i = low j = 2 * i + 1 while j <= higt: # 情况2:i已经是 ...
- Python 实现转堆排序算法原理及时间复杂度(多图解释)
原创文章出自公众号:「码农富哥」,欢迎转载和关注,如转载请注明出处! 堆基本概念 堆排序是一个很重要的排序算法,它是高效率的排序算法,复杂度是O(nlogn),堆排序不仅是面试进场考的重点,而且在很多 ...
- 堆排序算法 java 实现
堆排序算法 java 实现 白话经典算法系列之七 堆与堆排序 Java排序算法(三):堆排序 算法概念 堆排序(HeapSort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,可以利用数组的特 ...
随机推荐
- windowsAPI popup trace tip(toolTip)
class UIHELPER_EXPORT ToolTipWindow : public chMessageHandler{ DECLARE_PROCESS_OBJECT(ToolTipWindow) ...
- MongoDB文档、集合、数据库简介
文档 概述 文档是MongoDB的核心概念,是数据的基本单元,非常类似于关系数据库中的行.在MongoDB中,文档表示为键值对的一个有序集.MongoDB使用Javascript shell,文档的表 ...
- AngularJS学习--- AngularJS中数据双向绑定(two-way data-binding) orderBy step4
1.切换工作目录 git checkout step- #切换分支,切换到第4步 npm start #启动项目 2.代码 app/index.html Search: <input ng-mo ...
- frame和bounds的区别与联系
首先先看一下下面两个属性的代码实现: -(CGRect)frame{ return CGRectMake(self.frame.origin.x,self.frame.origin.y,self.fr ...
- linux 系统下,如何清空文件内容
最近用 crontab命令 做了一些 同步任务,可后期同步任务的代码没用了,于是,我就直接删除了 代码(对应的jar包),但是 crontab -e 的命令行没有删除 ,以后,每天我的Azure vm ...
- Android学习之 Intent详解
一. Intent 作用 Intent 是一个将要执行的动作的抽象的描述,一般来说是作为参数来使用,由Intent来协助完成android各个组件之间的通讯.比如说调用startActivity()来 ...
- hdu 5792(树状数组,容斥) World is Exploding
hdu 5792 要找的无非就是一个上升的仅有两个的序列和一个下降的仅有两个的序列,按照容斥的思想,肯定就是所有的上升的乘以所有的下降的,然后再减去重复的情况. 先用树状数组求出lx[i](在第 i ...
- canvas 画六边形边框
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Python模块——bisect
bisect是python内置的模块,主要用于对有序列进行操作.具体用法如下: 模块导入:import bisect 内容查看:dir(bisect) 这个模块包含了: 五个变量:builtins, ...
- php 生日提醒程序
<?php $startdate=time(); //当前时间 $birth="2013-05-13"; // 出生日期 $arr=explode(" ...