PHP使用二叉堆实现的具体算法模式

PHP使用二叉堆实现的具体算法模式
前言

在以前的工作或面试中常常会遇到的一个问题,如何实现大规模的TopN,是一个非常大的结果集,并迅速找到前10或前100的数量,同时确保内存速度的效率,我们可能第一个想法是使用排序,然后10拦截或前100,而排名的体积不是特别大,没有任何问题,但只要大量来完成这项任务是不可能的,例如,有一个数组或一个文本文件,数以百万计的数字,这不是全部读入内存,所以排名不解决这一问题的最佳方案,这里我们使用PHP实现一小堆的顶部来解决这个问题。

两叉桩

二叉堆是一个特殊的堆,两叉堆是完全二叉树或接近完全二叉树,两叉堆二,最大堆和最小堆,最大堆:父节点值总是大于或等于任何子节点键;最小堆:父节点密钥总数小于或等于任何子节点键。

小堆顶(图片来自网络
一个数组来表示二叉堆一般使用(见图表),例如,在数组中的位置是根节点0,节点位置分别在第n 2n+1和2n + 2,因此,零阶的子节点在1和2, 1在3和4的子节点的位置,和所以,这种存储方式查找父节点和子节点。

这里的概念是不是说,如果有问题的二叉堆可以在一个好的数据结构,我们有以下的TopN使用PHP代码和解决,为了看到这里的差异去下的排序结果的方法
使用快速排序算法实现TopN

为了测试/运行内存
ini_set('memory_limit ','2024m);

实现快速排序功能
功能quick_sort(数组){
长度=计数(数组);
left_array美元=阵();
right_array美元=阵();
如果(长度< = 1){
返回数组;
}
$ = $数组{ 0 };
($ i = 1;$ i $ $长度;$ + +){
如果($ $)
right_array美元{ } =数组{ $我};
其他{ }
left_array美元{ } =数组{ $我};
}
}
left_array = quick_sort美元(美元left_array);
right_array = quick_sort美元(美元right_array);
返回array_merge($ right_array,阵列($键),left_array美元);
}

500w重复数 / /结构
($ i = 0;$ i < 5000000;$ + +){
numarr美元{ } = $我;
}
他们扰乱 /
洗牌($ numarr);

我们发现TOP10 / /现在从内数量最多。
var_dump(时间());
print_r(array_slice(quick_sort(合所有),0));
var_dump(时间());
运行后的结果
你可以看到,上面打印的TOP10的结果,输出下的运行时间,99s左右,但这只是500w数都可以被加载到内存中。如果我们有5亿5kW或文件中的数字,会有一些问题。

采用二叉堆算法实现TopN
实施过程是:
1、第一次读到10或100数字的数组,这是我们的流量数。
2。调用生成一个小顶堆函数,并生成一个小顶堆结构,此时必须是最小值。
三.所有剩余的数字都从文件或数组中遍历。
4。每个遍历一个都与堆顶部的大小进行比较。如果它小于堆顶元素,如果它大于堆顶元素,它将被替换
5。在替换堆顶元素之后,通过调用生成的小堆函数来生成小顶堆,因为需要找到最小的顶堆函数。
6、重复步骤4 ~ 5,当遍历结束,我们没有在堆的顶部是最大的流量,因为小顶堆总是把最出的最小,与顶尖的快速调整,只有相对的调整,只要根节点小于。节点可以是。
7,在最坏情况下的TOP10算法的复杂度,其中每个遍历一个号码,如果更换堆栈顶部,需要调整至10倍,比排序的速度,但也不是所有的内容都读到内存中,可以了解一个线性遍历的成果。

在堆的顶部生成一个小函数
功能堆($ ARR,$ IDX){
为左=(美元指数< 1)+ 1;
$权=($ IDX << 1)+ 2;

如果(!ARR {左}美元美元){
返回;
}

如果($ ARR { $权} { } <对ARR美元美元美元美元ARR {左}){
$ l = $;
其他{ }
美元=左;
}

If ($arr{$idx} > $arr{$l}) {
TMP =美元美元美元IDX ARR { };
ARR { } =美元美元美元美元IDX ARR { L };
{ } = L ARR美元美元美元的TMP;
堆($ ARR,$ L);
}
}

为了保证在上述 /一致性,也不构成500w重复数
*
当然,这个数据集并不总是存储在内存中,它也可以在
在文件中,因为我们没有全部加载到内存中
行排序
* /
($ i = 0;$ i < 5000000;$ + +){
numarr美元{ } = $我;
}
他们扰乱 /
洗牌($ numarr);

取出数组10
toparr美元= array_slice(numarr美元,10);

获取最后一个子节点索引位置
因为在构建堆的小/顶部时,是从最后一个左或右节点位置构建的。
从开始到移动结构(图表的顶部)
$ IDX =地板(计数($ toparr) / 2)- 1;

生成一个小的堆顶
为($我= $ IDX;我> = 0美元美元;我--){
堆(toparr美元美元,我);
}

var_dump(时间());
在这里您可以看到,其余的都是元素遍历的开始。
为($我=计数($ toparr);$我<计数(numarr美元美元);i++){
每一个都是对遍历/堆栈元素进行比较大小。
如果($ numarr { $我} > $ toparr { 0 }){
如果超过了堆/元素替换的顶部
为toparr { 0 } = {我} numarr美元美元;
*
再活化生成小顶堆函数进行维修,但这次是从堆的顶部
指数的位置开始从顶部保持,因为我们只是把顶部的桩。
根据根节点替换元素,其余元素小于左节点和右节点。
这就是我们所说的,这只是一个相对的调整。
不是所有的调整
* /
堆(toparr美元,0);
}
}
var_dump(时间());
运行后的结果
你可以看到结果是TOP10,但时间只有约1s,与记忆和时间效率能满足我们的要求,而且对排名比最好的事情是,不是所有的数据集的读为记忆,因为我们不需要排序,与上面的论证,所以直接在500W元素的存储结构,但我们可以把它全部转移到文件,然后读取一行比较,因为我们的高级数据结构的小核心是线性的非常小的内存遍历器内部结构进行比较,最后TopN。

总结

最后一点要说的是算法+数据结构是非常重要的,一个好的算法可以大大提高我们的效率。希望本文的内容能给大家的学习或工作带来一定的帮助。如果有任何疑问,您可以留言交流,谢谢您的支持
免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部