美文网首页PHP数据结构
PHP优先队列、二叉堆、大顶堆、小顶堆

PHP优先队列、二叉堆、大顶堆、小顶堆

作者: 江月照我眠 | 来源:发表于2021-12-07 12:05 被阅读0次

一 、基本数据结构

堆:
  • 堆是一棵完全二叉树,
  • 根节点的值总是不大于或者不小于子节点的值

将根结点最大的堆叫做最大堆、大顶堆或大根堆,根结点最小的堆叫做最小堆、小顶堆或小根堆。常见的堆有二叉堆、斐波那契堆
通常堆顶节点都是最大或者最小的,在解决特殊问题时,先弹出堆顶元素非常有优势

栈:

先进后出(FILO),就像一个敞口向上的容器,只能将后进入容器的先弹出。

队列:

先进先出(FIFO),跟栈相反,队列就像一根上下贯通的水管,只能将先流入水管的水流出去。

二、优先级队列

优先队列也是一种数据结构,通过加权值进行排序,PHP核心库提供了SplPriorityQueue对象来实现。
优先队列内部是用Heap:堆这种数据结构来实现的,默认是大顶堆(MaxHeap)。

1. 常规用法(大顶堆)
$queue = new SplPriorityQueue;

// 插入堆,并自动筛选和排序
// 接受2个参数,insert(值, 优先级)
$queue->insert('A', 3);
$queue->insert('B', 9);
$queue->insert('C', 2);
$queue->insert('D', 5);

// 堆中元素的个数
$count = $queue->count(); // 此时为4

// 返回堆顶的节点
$top = $queue->top(); // 堆不变

/**
* 设置元素出队模式
* SplPriorityQueue::EXTR_DATA 仅提取值
* SplPriorityQueue::EXTR_PRIORITY 仅提取优先级
* SplPriorityQueue::EXTR_BOTH 提取数组包含值和优先级
*/
$queue->setExtractFlag(SplPriorityQueue::EXTR_BOTH);

// 从堆顶提取元素,并重新筛选和排序
$queue->extract(); // 此时B被取出,堆顶元素重置为D
$queue->extract(); // 此时D被取出,堆顶元素重置为A
$queue->extract(); // 此时A被取出,堆顶元素重置为C
$queue->extract(); // 此时C被取出,堆中元素全部取出

// 判断堆是否为空
$status = $queue->isEmpty(); // 结果为true

// 迭代指针相关

// 因为优先队列是堆实现的,所以rewind实际没什么用,他永远指向堆顶指针,current也永远等于堆顶的值
// 故而extract相当于current(返回当前节点)和next(指向下一个节点)两个操作

// 返回当前节点
$current = $queue->current();

// 指针指向下一个节点
$queue->next();

// 返回堆中堆中是否还有节点
while ($queue->valid()) {
    $current = $queue->current();
    $queue->next();
}

2. 改成小顶堆(MinHeap)

优先队列改成小顶堆,需要重写compare方法,将比较值对调,即可切换小顶堆和大顶堆。

/*
 * 小顶堆
 */
class MyMinHeap extends SplPriorityQueue {
    function compare($value1, $value2) {
        // if ($value1 === $value1) return 0;
        // return $value1 < $value2 ? -1 : 1; 
        // return $value1 - $value2; // 高优先级优先
        return $value2 - $value1; // 低优先级优先
    }
}

$queue = new MyMinHeap;

// 插入堆,并自动筛选和排序
// insert接受2个参数,key在前,value在后,vaue为排序的权重值
$queue->insert('A', 3);
$queue->insert('B', 9);
$queue->insert('C', 2);
$queue->insert('D', 5);

$queue->extract(); // 此时C被取出,堆顶元素重置为A
$queue->extract(); // 此时A被取出,堆顶元素重置为D
$queue->extract(); // 此时D被取出,堆顶元素重置为B
$queue->extract(); // 此时B被取出,堆中元素全部取出

$status = $queue->isEmpty(); // 结果为true

三、堆、大顶堆和小顶堆

堆就是为了实现优先队列而设计的一种数据结构,它分为大顶堆和小顶堆,PHP核心库提供了大顶堆SplMaxHeap小顶堆SplMinHeap两种类可供直接使用,他们都是由SplHeap抽象类实现的。

  • 简单数据
/**
 * 自定义:最小堆/小顶堆
 * 低优先级优先弹出
 * 等同于系统自带的SplMinHeap
 */
class MyMinHeap extends SplHeap
{
    // 比较元素,以便在筛选时将它们正确地放在堆中,
    // 如果value1大于value2则为正整数,如果相等则为0,否则为负整数
    function compare($value1, $value2) { 
        return $value2 - $value1;
    } 
}

/**
 * 自定义:最大堆/大顶堆
 * 高优先级优先弹出
 * 等同于系统自带的SplMaxHeap
 */
class MyMaxHeap extends SplHeap
{
    // 比较元素,以便在筛选时将它们正确地放在堆中,
    // 如果value1小于value2则为正整数,如果相等则为0,否则为负整数
    function compare($value1, $value2) { 
        return $value1 - $value2;
    } 
}

$minHeap = new MyMinHeap;
// 插入元素,insert(值)
$minHeap->insert(3);
$minHeap->insert(2);
$minHeap->insert(4);
$minHeap->insert(1);
// 取出元素
$minHeap->extract(); // 1被取出
$minHeap->extract(); // 2被取出
$minHeap->extract(); // 3被取出
$minHeap->extract(); // 4被取出

$maxHeap = new MyMaxHeap;
// 插入元素
$maxHeap->insert(3);
$maxHeap->insert(2);
$maxHeap->insert(4);
$maxHeap->insert(1);
// 取出元素
$maxHeap->extract(); // 4被取出
$maxHeap->extract(); // 3被取出
$maxHeap->extract(); // 2被取出
$maxHeap->extract(); // 1被取出

  • 复杂数据
/**
 * 自定义:最小堆/小顶堆
 * 低优先级优先弹出
 * 等同于系统自带的SplMinHeap
 */
class MyMinHeap extends SplHeap
{
    function compare($arr1, $arr2) { 
        $value1 = array_values($arr1);
        $value2 = array_values($arr2);
        if ($value2[0] === $value1[0]) return 0;
        return $value2[0] < $value1[0] ? -1 : 1;
    } 
}

/**
 * 自定义:最大堆/大顶堆
 * 高优先级优先弹出
 * 等同于系统自带的SplMaxHeap
 */
class MyMaxHeap extends SplHeap
{
    function compare($arr1, $arr2) { 
        $value1 = array_values($arr1);
        $value2 = array_values($arr2);
        // if ($value2[0] === $value1[0]) return 0;
        // return $value2[0] > $value1[0] ? -1 : 1;// 高优先级优先弹出
        return $value1[0] - $value2[0];
    } 
}

$minHeap = new MyMinHeap;
// 插入元素,insert(值)
$minHeap->insert(['A' => 3]);
$minHeap->insert(['B' => 2]);
$minHeap->insert(['C' => 4]);
$minHeap->insert(['D' => 1]);
// 取出元素
$minHeap->extract(); // D被取出
$minHeap->extract(); // B被取出
$minHeap->extract(); // A被取出
$minHeap->extract(); // C被取出

$maxHeap = new MyMaxHeap;
// 插入元素
$maxHeap->insert(['A' => 3]);
$maxHeap->insert(['B' => 2]);
$maxHeap->insert(['C' => 4]);
$maxHeap->insert(['D' => 1]);
// 取出元素
$maxHeap->extract(); // C被取出
$maxHeap->extract(); // A被取出
$maxHeap->extract(); // B被取出
$maxHeap->extract(); // D被取出

总结:

  • 优先队列SplPriorityQueue的insert接受两个参数,第一个参数为值,第二个参数为权重
  • 大顶堆SplMaxHeap和小顶堆SplMinHeap均实现了SplHeap抽象类,通过重写compare方法来区分大/小顶堆
  • 大顶堆和小顶堆只接受一个参数,需要注意传不同类型的数据时,compare方法的写法需要对应地进行修改

相关文章

  • PHP优先队列、二叉堆、大顶堆、小顶堆

    一 、基本数据结构 堆: 堆是一棵完全二叉树, 根节点的值总是不大于或者不小于子节点的值 将根结点最大的堆叫做最大...

  • Java数据结构 - 堆

    堆 堆是一棵完全二叉树,如下图,也是一个优先队列。 小顶堆:所有节点的左右孩子节点都小于或者等于父节点 大顶堆:所...

  • 堆的应用

    堆的应用一:优先级队列 将优先级的之分的数据存入堆中(小顶堆或者大顶堆),堆顶即优先级最搞的数据,当需要的时候直接...

  • [数据结构与算法-iOS 实现]优先级队列

    优先级队列 可以利用二叉堆来实现优先级队列,比如我们用大顶堆,堆顶为我们的最大元素,可以理解为优先级最高的元素,我...

  • 优先队列关键字总结

    性质 优先队列为二叉树,用连续的数组存储 分类 小顶堆:每个节点的子节点大于等于其父节点 大顶堆:每个节点的子节点...

  • 堆在java中的应用--PriorityQueue

    堆的特点 堆是一种完全二叉树的模拟,堆一般是基于数组的实现,堆分大顶堆和小顶堆,大顶堆就是堆顶是最大的数据,然后子...

  • 堆-Heap

    堆-Heap 堆的基本接口设计 二叉堆(最大堆) 大顶堆-添加 大顶堆-删除 删除堆顶元素的同时插入一个新元素 大...

  • 详解堆排序算法

    什么是堆 堆首先是一个完全二叉树,堆分为大顶堆和小顶堆;大顶堆 :每个节点的值大于或等于其左右孩子节点的值,称为大...

  • 看图说话数据结构之二项队列(优先队列)——原理解析

    数据结构之二叉堆(优先队列)——原理解析,数据结构之二叉堆(优先队列)——java实现,数据结构之左式堆(优先队列...

  • 剑指offer 数据流中的中位数

    建立大顶堆和小顶堆

网友评论

    本文标题:PHP优先队列、二叉堆、大顶堆、小顶堆

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