SPL数据结构2-Heap,最大堆,最小堆

堆是一种常见的数据结构。其底层就是一个用数组实现的二叉树。但是没有父指针和子指针。 根据堆属性来进行排序。分为最小堆和最大堆。

  • 最小堆:父节点的值比每个子节点的值都要小
  • 最大堆:父节点的值比每一个子节点的值都要大

一般应用在以下场景:

  • 快速排序(取最大值 最小值)
  • 优先队列

最大堆/最小堆

spl中SplHeap抽象类实现了堆数据结构。SplMaxHeap和SplMinHeap继承自SplHeap,分别用来实现最大堆和最小堆。以下代码以最大堆为例做说明,最小堆的时候和最大堆类似

// 最大堆
$maxheap = new SplMaxHeap();
// 插入节点并重建堆
$maxheap->insert(12);
$maxheap->insert(3);
$maxheap->insert(222);
$maxheap->insert(2);
$maxheap->insert(312);
$maxheap->insert(3);
$maxheap->insert(13);
$maxheap->insert(32);
$maxheap->insert(3);
$maxheap->insert(1);

// 最大推顶层元素:312
echo "最大推顶层元素:" . $maxheap->top() . PHP_EOL;

// extract提取顶层元素
// 取出节点并重建堆 
// extract:312
echo "extract:" . $maxheap->extract() . PHP_EOL;
// extract:222
echo "extract:" . $maxheap->extract() . PHP_EOL;
// extract:32
echo "extract:" . $maxheap->extract() . PHP_EOL;

echo "判断是否是空堆:" . PHP_EOL;
// bool(false)
var_dump($maxheap->isEmpty());
// 当堆长度为0 的时候该堆为空堆
// 当前堆长度:7
echo "当前堆长度:" . $maxheap->count() . PHP_EOL;

实现自定义推排序

很多时候,单纯的数字大小比较不能满足我们对于堆数据结构的要求。比如我们要基复杂数组实现堆排序。SplHeap 类提供了compare抽象方法,只要我们实现自己的compare方法,就可以对任意数据类型进行最小堆最大堆排序

class MmaxHead extends SplHeap
{

    /**
     * 假设推中为关联数组 保存学生信息 根据成绩排名
     * ['name'=>'Bob',score=>99.2]
     * 
     * @param mixed $value1
     * @param mixed $value2
     * 
     * @return int
     */
    protected function compare($value1, $value2)
    {
        if ($value1['score'] > $value2['score']) {
            return 1;
        } elseif ($value1['score'] < $value2['score']) {
            return -1;
        } else {
            return 0;
        }

    }
}

$myheap = new MmaxHead();
$myheap->insert(['name' => "bob1", "score" => 65]);
$myheap->insert(['name' => "bob2", "score" => 34.3]);
$myheap->insert(['name' => "bob3", "score" => 99.3]);
$myheap->insert(['name' => "bob4", "score" => 23.4]);
$myheap->insert(['name' => "bob5", "score" => 55]);
$myheap->insert(['name' => "bob6", "score" => 66]);


// 成绩最高的是
//array(2) {
//  ["name"]=>
//  string(4) "bob3"
//  ["score"]=>
//  float(99.3)
//}

echo "成绩最高的是" . PHP_EOL;
var_dump($myheap->top());

echo "依次排名:" . PHP_EOL;
while (!$myheap->isEmpty()) {
    var_dump($myheap->extract());
}

优先队列

spl中已经为我们提供了优先队列SplPriorityQueue。SplPriorityQueue基于最大堆实现,即优先级越大越先出队。可以通过重写compare改为优先级小先出队(最小堆),同样也可以通过集成重写compare来实现自己的业务逻辑

$objPQ = new SplPriorityQueue();

$objPQ->insert('A',3);
$objPQ->insert('B',6);
$objPQ->insert('C',1);
$objPQ->insert('D',2);

// 优先队列长度: 4
echo "优先队列长度: ".$objPQ->count().PHP_EOL;


/**
 * 设置元素出队模式
 * SplPriorityQueue::EXTR_DATA 仅提取值
 * SplPriorityQueue::EXTR_PRIORITY 仅提取优先级
 * SplPriorityQueue::EXTR_BOTH 提取数组包含值和优先级
 */
// 默认
$objPQ->setExtractFlags(SplPriorityQueue::EXTR_DATA);
// top 提取值: B
echo "top 提取值: ".$objPQ->top().PHP_EOL;

$objPQ->setExtractFlags(SplPriorityQueue::EXTR_PRIORITY);
// top 提取优先级: 6
echo "top 提取优先级: ".$objPQ->top().PHP_EOL;

$objPQ->setExtractFlags(SplPriorityQueue::EXTR_BOTH);
// top 返回数组 包括值和优先级: 
//array(2) {
//  ["data"]=>
//  string(1) "B"
//  ["priority"]=>
//  int(6)
//}
echo "top 返回数组 包括值和优先级: ".PHP_EOL;
var_dump($objPQ->top());

//遍历:
//BADC
$objPQ->setExtractFlags(SplPriorityQueue::EXTR_DATA);
while($objPQ->valid()){
    print_r($objPQ->current());
    $objPQ->next();
}

上一篇:双向链表,堆栈,队列
下一篇:SPL 数据结构3-SplFixedArray

后端程序员

144 声望
1 粉丝
0 条评论
推荐阅读
GO 实现优先队列
在php中提供了SplPriorityQueue来实现优先队列操作。在Go中,虽然没有直接提供优先队列的实现,不过通过标准库container/heap可以很方便的实现一个简单的优先队列。

tim_xiao阅读 782

php实现只需要一个QQ号就可以获得用户信息
{代码...} DEMO:[链接]此处输入你的QQ号

TANKING27阅读 7.3k评论 5

初学后端,如何做好表结构设计?
这篇文章介绍了设计数据库表结构应该考虑的4个方面,还有优雅设计的6个原则,举了一个例子分享了我的设计思路,为了提高性能我们也要从多方面考虑缓存问题。

王中阳Go4阅读 1.7k评论 2

封面图
一分钟搞明白!快速掌握 Go WebAssembly
最近因为各种奇怪的原因,更多的接触到了 WebAssembly。虽然之前很多博客也翻过写过各种文章,但总感觉欠些味道。于是今天梳理了一版,和大家一起展开学习。

煎鱼4阅读 2.1k

面试官:请说一下如何优化结构体的性能?
使用内存对齐机制优化结构体性能,妙啊!前言之前分享过2篇结构体文章:10秒改struct性能直接提升15%,产品姐姐都夸我好棒 和 Go语言空结构体这3种妙用,你知道吗? 得到了大家的好评。这篇继续分享进阶内容:结...

王中阳Go4阅读 3.7k评论 2

封面图
深入理解MySQL索引底层数据结构
在日常工作中,我们会遇见一些慢SQL,在分析这些慢SQL时,我们通常会看下SQL的执行计划,验证SQL执行过程中有没有走索引。通常我们会调整一些查询条件,增加必要的索引,SQL执行效率就会提升几个数量级。我们有没...

京东云开发者3阅读 569

封面图
Laravel入门及实践,快速上手ThinkSNS+二次开发
【摘要】自从ThinkSNS+不使用ThinkPHP框架而使用Laravel框架之后,很多人都说技术门槛抬高了,其实你与TS+的距离仅仅只是学习一个新框架而已,所以,我们今天来说说Laravel的入门。

ThinkSNS1阅读 2.4k

后端程序员

144 声望
1 粉丝
宣传栏