关于堆排序和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实现的堆

  1 class Heap {
  2
  3
  4
  5     protected $listSize;
  6
  7     protected $tree;
  8
  9
 10
 11     public function __construct($list) {
 12
 13         $this->listSize = count($list);
 14
 15         $i = 1;
 16
 17         foreach ($list as $li) {
 18
 19             $this->tree[$i++] = $li;
 20
 21         }
 22
 23         unset($list);
 24
 25         $this->initHeap();
 26
 27     }
 28
 29
 30
 31     public function getSortedResult() {
 32
 33         $this->initHeap();
 34
 35         $this->sortHeap();
 36
 37         return $this->tree;
 38
 39     }
 40
 41
 42
 43     public function getHeapResult() {
 44
 45         return $this->tree;
 46
 47     }
 48
 49
 50
 51     public function getTopNode() {
 52
 53         return $this->tree[1];
 54
 55     }
 56
 57
 58
 59     public function setTopNode($value) {
 60
 61         $this->tree[1] = $value;
 62
 63         $this->adjustHeap(1, $this->listSize);
 64
 65     }
 66
 67
 68
 69     public function sortHeap() {
 70
 71         for ($end = $this->listSize; $end > 1; $end--) {
 72
 73             $this->swap($this->tree[1], $this->tree[$end]);
 74
 75             $this->adjustHeap(1, $end - 1);
 76
 77         }
 78
 79     }
 80
 81
 82
 83     private function initHeap() {
 84
 85         for ($start=floor($len / 2); $start >= 1; $start--) {
 86
 87             $this->adjustHeap($start, $this->listSize);
 88
 89         }
 90
 91     }
 92
 93
 94
 95     private function adjustHeap($start, $len) {
 96
 97         $tmp = $start;  // 临时变量,用于保存最大值或者最小值的下标索引
 98
 99         $lChildInx = $start * 2;
100
101         $rChildInx = $lChildInx + 1;
102
103         if ($start <= floor($len / 2)) {
104
105             if($lChildInx <= $len && $this->tree[$lChildInx] < $this->tree[$tmp]) {
106
107                 $tmp = $lChildInx;
108
109             }
110
111             if($rChildInx <= $len && $this->tree[$rChildInx] < $this->tree[$tmp]) {
112
113                 $tmp = $rChildInx;
114
115             }
116
117             if ($tmp != $start) {
118
119                 $this->swap($this->tree[$tmp], $this->tree[$start]);
120
121                 $this->adjustHeap($tmp, $len);
122
123             }
124
125         }
126
127     }
128
129
130
131     private function swap(&$a, &$b) {
132
133         $temp = $a;
134
135         $a = $b;
136
137         $b = $temp;
138
139     }
140
141
142
143 }

topK

 1 include ‘Heap.class.php‘;
 2
 3
 4
 5 $list = range(1,10000);
 6
 7 shuffle($list);
 8
 9 $k = 15;
10
11
12
13 $initHeapNodes = array_slice($list, 0, $k);
14
15 $heap = new Heap($initHeapNodes);
16
17
18
19 $n = count($list);
20
21
22
23 for ($i=$k; $i<$n; $i++) {
24
25     if ($list[$i] > $heap->getTopNode()) {
26
27         $heap->setTopNode($list[$i]);
28
29     }
30
31 }
32
33
34
35 print_r($heap->getSortedResult());
时间: 2024-11-05 17:12:24

关于堆排序和topK算法的PHP实现的相关文章

快速排序、归并排序、堆排序三种算法性能比较

快速排序.归并排序.堆排序三种排序算法的性能谁最好呢?网上查了一下说快速排序最快.其次是归并排序,最差的是堆排序:而理论上三种排序算法的时间复杂度都是O(nlogn),只不过快速排序最差的会达到O(n^2),但是数据的随机性会消除这一影响,今天就来实际比较一下: 1 #include <iostream> 2 #include<time.h> 3 using namespace std; 4 #define MAX 100000000 5 int data1[MAX],data2[

堆排序与优先队列&mdash;&mdash;算法导论(7)

1. 预备知识 (1) 基本概念     如图,(二叉)堆一个数组,它可以被看成一个近似的完全二叉树.树中的每一个结点对应数组中的一个元素.除了最底层外,该树是完全充满的,而且从左向右填充.堆的数组A包括两个属性:A.length给出了数组的长度:A.heap-size表示有多少个堆元素保存在该数组中(因为A中可能只有部分位置存放的是堆的有效元素).     由于堆的这种特殊的结构,我们可以很容易根据一个结点的下标i计算出它的父节点.左孩子.右孩子的下标.计算公式如下: parent(i) =

堆排序(摘自算法导论)

(二叉)堆是一个数组,他可以被看成一个近似的完全二叉树.树上的每一个节点对应数组中的一个元素,除了最底层之外,该树是完全填满的,而且是从左向右填充.表示堆的数组A包括两个属性,A.length给出数组元素的个数,A.heap-size表示有多少个堆元素存储在该数组中.也就是说,虽然A[1..A.length]可能都有数据,但只有A[1..A.heap-size]中存放的是堆的有效元素.0<=A.heap-size<=A.length.树的根节点是A[1],这样给定一个节点的下标i,我们很容易计

堆排序原理及算法实现(最大堆)

堆排序 堆排序是利用堆的性质进行的一种选择排序.以下先讨论一下堆. 1.堆 堆实际上是一棵全然二叉树,其不论什么一非叶节点满足性质: Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]或者Key[i]>=Key[2i+1]&&key>=key[2i+2] 即不论什么一非叶节点的keyword不大于或者不小于其左右孩子节点的keyword. 堆分为大顶堆和小顶堆,满足Key[i]>=Key[2i+1]&&ke

Hadoop读书笔记(十四)MapReduce中TopK算法(Top100算法)

Hadoop读书笔记系列文章:http://blog.csdn.net/caicongyang/article/category/2166855 (系列文章会逐步修整完成,添加数据文件格式预计相关注释) 1.说明: 从给定的文件中的找到最大的100个值,给定的数据文件格式如下: 533 16565 17800 2929 11374 9826 6852 20679 18224 21222 8227 5336 912 29525 3382 2100 10673 12284 31634 27405 1

堆排序:什么是堆?什么是最大堆?二叉堆是什么?堆排序算法是怎么样的?PHP如何实现堆排序?

本文标签:  堆排序 php php算法 堆排序算法 二叉堆 数据结构 REST   服务器 什么是堆 这里的堆(二叉堆),指得不是堆栈的那个堆,而是一种数据结构. 堆可以视为一棵完全的二叉树,完全二叉树的一个"优秀"的性质是,除了最底层之外,每一层都是满的,这使得堆可以利用数组来表示,每一个结点对应数组中的一个元素. 数组与堆之间的关系 二叉堆一般分为两种:最大堆和最小堆. 什么是最大堆 堆中每个父节点的元素值都大于等于其孩子结点(如果存在),这样的堆就是一个最大堆 因此,最大堆中的

详谈排序算法之选择类排序(两种方法实现堆排序)

   今天我们再来讨论一下选择类排序,选择类排序分为:简单排序,树形选择排序和堆排序.但我们主要说的是简单和堆排序两个,因为树形选择排序使用了较多的辅助空间,以及和∞进行多余比较,为弥补树型选择排序的这些缺点, J.W.J.Williams 在 1964 年提出了进一步的改进方法,即堆排序.对于我个人而言..一开始并不是很理解它的算法思想,纠结了许久.在网上查找资料的时候发现这位大神的文章思路十分清晰,而且把创建堆以及堆化数组的算法讲解的十分详细.如果有不明白堆排序思路的,可以先看看这篇文章~堆

排序算法之堆排序(Heapsort)解析

一.堆排序的优缺点(pros and cons) (还是简单的说说这个,毕竟没有必要浪费时间去理解一个糟糕的的算法) 优点: 堆排序的效率与快排.归并相同,都达到了基于比较的排序算法效率的峰值(时间复杂度为O(nlogn)) 除了高效之外,最大的亮点就是只需要O(1)的辅助空间了,既最高效率又最节省空间,只此一家了 堆排序效率相对稳定,不像快排在最坏情况下时间复杂度会变成O(n^2)),所以无论待排序序列是否有序,堆排序的效率都是O(nlogn)不变(注意这里的稳定特指平均时间复杂度=最坏时间复

浅析STL算法中的堆排序

堆结构简述 了解过数据结构的人,应该对堆结构不陌生,堆的底层是使用数组来实现的,但却保持了二叉树的特性.堆分为两种,最大堆和最小堆,以最大堆为例,最大堆保持了根结点大于两个左右两个孩子,同时所有子树一次类推.由于堆底层是数组结构,这里从跟结点开始,按照层序依次走到最后一个结点,结点下标分贝为0~N-1.结构如下图: 上图中,紫色表示的是该元素在数组中的下标,可以看到,每个结点的值总是大于它的左右孩子,这里并没有规定左右孩子的大小关系,也没有规定不是同一棵树之间结点的大小关系.这就是最大堆.同时这