1. 程式人生 > >二叉堆 binary heap (2) 利用小根堆求最大 top k

二叉堆 binary heap (2) 利用小根堆求最大 top k

使操作被快速執行的性質是堆序(heap order)性. 由於我們想要快速地找出最小元,因此最小元應該在根上.

類似的,可以宣告一個max堆,找到和刪除最大元

     在一個堆中,對於每一個節點X,X的parent中的關鍵字<=X中的關鍵字, 根節點除外(它沒有parent).

* Heap/BinMinHeap.php

<?php
/**
 * 完全二叉樹的陣列實現
 * ==============================
 *         A
 *       /   \
 *     B      C
 *    / \    / \
 *   D  E   F  G
 *  /\  /
 * H I  J
 * ===============================
 * _ A B C D E F G H I J   _  _  _
 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13
 */
namespace Heap;

use util\Comparator;

class BinMinHeap {
    /** @var  int */
    protected $capacity;

    /** @var  int */
    protected $size;

    /** @var \SplFixedArray */
    protected $elements;

    /** @var Comparator */
    protected $comparator;

    const MIN_PQSIZE = 1;
    const MIN_DATA = null;

    public function __construct(int $maxElements, Comparator $cmp) {
        if ($maxElements < self::MIN_PQSIZE) {
            throw new \AssertionError("Priority queue size is too small");
        }
        $this->elements = new \SplFixedArray($maxElements + 1);
        $this->capacity = $maxElements;
        $this->size = 0;
        /* dumb position 0 */
        $this->elements[0] = self::MIN_DATA;

        $this->comparator = $cmp;
    }

    public function isFull() {
        return $this->size >= $this->capacity;
    }

    public function insert($x) {
        if ($this->isFull()) {
            throw new \RuntimeException("Priority queue is full");
        }
        for ($i = ++$this->size; $this->elements[$i>>1] > $x; $i >>= 1) {
            $this->elements[$i] = $this->elements[ $i>>1 ];
        }
        $this->elements[ $i ] = $x;
    }

    public function isEmpty() {
        return $this->size === 0;
    }

    public function deleteMin() {
        if ($this->isEmpty()) {
            return $this->elements[0];
        }
        $minElement = $this->elements[1];
        $lastElement = $this->elements[$this->size--];

        for ($i = 1; $i * 2 <= $this->size; $i = $child) {
            /* find smaller child */
            $child = $i * 2;
            if ($child !== $this->size &&
                $this->comparator->lessThan(
                    $this->elements[$child+1], $this->elements[$child])) {
                $child++;
            }
            /* Percolate one level */
            if ($this->comparator->greeterThan($lastElement, $this->elements[$child])) {
                $this->elements[$i] = $this->elements[$child];
            } else {
                break;
            }
        }
        $this->elements[$i] = $lastElement;
        return $minElement;
    }

    public function findMin() {
        return $this->isEmpty() ? $this->elements[0] : $this->elements[1];
    }

    public function __destruct() {
        for ($i = $this->size-1; $i >= 0; $i--) {
            unset($this->elements[$i]);
        }
        $this->elements = null;
    }
    public function makeEmpty() {
        $this->size = 0;
    }

    public function getComparator() {
        return $this->comparator;
    }

    public function __toString() {
        if (0 === $this->size) {
            $s = "[]";
        } else {
            $s = '[';
            for ($i = 1, $last = $this->size+1; $i < $last; $i++) {
                $s .= json_encode($this->elements[$i]).',';
            }
            $s[strlen($s)-1] = ']';
        }
        return sprintf("{capacity: %d, size: %d, elements: %s}", $this->capacity, $this->size, $s);
    }

    public function getElements() {
        $e = [];
        for ($i = 1, $last = $this->size+1; $i < $last; $i++) {
            $e[] = $this->elements[$i];
        }
        return $e;
    }
}

* Heap/TopK.php

<?php
/**
 * Created by PhpStorm.
 * User: Mch
 * Date: 2018/11/3
 * Time: 2:50 PM
 */

namespace Heap;

use util\Comparator;

class TopK {

    /** @var  BinMinHeap */
    private $heap;

    public function __construct(array $a, int $k, Comparator $cmp = null) {
        if ($k < 1 || $k > count($a)) {
            throw new \LengthException('k < 1 or > count($a)');
        }
        if (is_null($cmp)) {
            $cmp = new Comparator();
        }
        $heap = new BinMinHeap($k, $cmp);
        while ( ! $heap->isFull() ) {
            $heap->insert(current($a));
        }
        while ( ($c = current($a)) !== false ) {
            if ( ! $heap->getComparator()->lessThan($c, $heap->findMin()) ) {
                $heap->deleteMin();
                $heap->insert($c);
            }
            next($a);
        }
        $this->heap = $heap;
    }

    public function insert($x) {
        if (! $this->heap->getComparator()->lessThan($x, $this->heap->findMin()) ) {
            $this->heap->deleteMin();
            $this->heap->insert($x);
        }
    }

    public function bulkInsert(array $a) {
        foreach ($a as $v) {
            $this->insert($v);
        }
    }

    public function getElements() {
        return $this->heap->getElements();
    }

    public function __toString() {
        return $this->heap->__toString();
    }
}

* util/Comparator.php

<?php
namespace util;

class Comparator {
    /** @var callable */
    protected $compare;

    public function __construct(callable $compareFunction = null) {
        if (is_null($compareFunction)) {
            $this->compare = function($a, $b) {
                if ($a === $b) {return 0;}
                return $a > $b ? 1 : -1;
            };
            return;
        }
        $this->compare = $compareFunction;
    }
    /*** @return bool */
    public function equal($a, $b) {
        return call_user_func($this->compare, $a, $b) === 0;
    }

    /*** @return bool */
    public function lessThan($a, $b) {
        return call_user_func($this->compare, $a, $b) < 0;
    }

    /*** @return bool */
    public function greeterThan($a, $b) {
        return call_user_func($this->compare, $a, $b) > 0;
    }

    /*** @return bool */
    public function lessThanOrEqual($a, $b) {
        return $this->lessThan($a, $b) || $this->equal($a, $b);
    }

    /*** @return bool */
    public function greeterThanOrEqual($a, $b) {
        return $this->greeterThan($a, $b) || $this->equal($a, $b);
    }

    public function reverse() {
        $compareOriginal = $this->compare;
        $this->compare = function ($a, $b) use ($compareOriginal) {
            return $compareOriginal($b, $a);
        };
    }
}

* autoload.php

<?php
$prefixList = ['Heap', 'util'];

array_walk($prefixList, function($prefix) {
    spl_autoload_register(function($class) use ($prefix) {
        $base_dir = __DIR__ . DIRECTORY_SEPARATOR. str_replace('\\', '/', $prefix);
        // echo $base_dir.PHP_EOL;
        $len = strlen($prefix);
        if (strncmp($prefix, $class, $len) !== 0) {
            return;
        }
        $relative_class = substr($class, $len);
        $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
        // echo $file.PHP_EOL;
        if (!file_exists($file)) {
            throw new InvalidArgumentException($file.' does not exist');
        }
        require $file;
    });
}, null);

* index.php

<?php
include './autoload.php';

use Heap\TopK;
use util\Comparator;

// 求出現頻率最高的前2個字母
$a = [
    ['char'=> 'c', 'freq'=> 12],
    ['char'=> 'e', 'freq'=> 16],
    ['char'=> 'b', 'freq'=>9],
    ['char'=> 'd', 'freq'=> 13],
    ['char'=> 'a', 'freq'=>5],
    ['char'=> 'f', 'freq'=> 45]
];
$b = new TopK($a, 2, new Comparator(
        function($a, $b) {return $a['freq'] - $b['freq'];}
    ));
echo json_encode($b->getElements()).PHP_EOL;

$b->bulkInsert([
    ['char' => 'g', 'freq' => 50],
    ['char' => 'h', 'freq' => 40],
]);
echo json_encode($b->getElements()).PHP_EOL;
echo $b.PHP_EOL;
unset($a, $b);

// 去掉空格 求ASCII最大的3個字母
$s = "The SplPriorityQueue class";
$s = preg_replace('/\s+/', '', $s);
for ($i = 0, $n = strlen($s); $i < $n; $i++) {
    $s[$i] = chr( ord($s[$i]) & 0xdf );
}
echo $s.PHP_EOL; // THESPLPRIORITYQUEUECLASS
$a = str_split($s);
$b = new TopK($a, 3, new Comparator(function($a, $b) {
    return strcmp($a, $b);
}));

// ACEEEHIILLOPPQRRSSSTTUUY
echo implode('', $b->getElements()).PHP_EOL;  // UYU

* test

$ php index.php 

[{"char":"e","freq":16},{"char":"f","freq":45}]

[{"char":"f","freq":45},{"char":"g","freq":50}]

{capacity: 2, size: 2, elements: [{"char":"f","freq":45},{"char":"g","freq":50}]}

THESPLPRIORITYQUEUECLASS

UYU

相關推薦

binary heap (2) 利用 top k

使操作被快速執行的性質是堆序(heap order)性. 由於我們想要快速地找出最小元,因此最小元應該在根上. 類似的,可以宣告一個max堆,找到和刪除最大元      在一個堆中,對於每一個節點X,X的parent中的關鍵字<=X中的關鍵字, 根節點除外(它沒有p

樹(建立、遍歷、樹的深度和深度)

樹的引出最初是由二分查詢的原理引出來的,一般順序查詢演算法的複雜度為O(N),而一般二分查詢的複雜度為logN 一個二分查詢演算法可以用一顆查詢樹來表示,樹的根結點為順序陣列的中點,這樣依次查詢效率等同於二分查詢演算法 一般的樹用陣列表示或連結串列表示都會造成空間的浪費,而

【BZOJ3625】【CF438E】小朋友和樹 NTT 生成函式 多項式開 多項式

題目大意   考慮一個含有n個互異正整數的序列c1,c2,…,cn。如果一棵帶點權的有根二叉樹滿足其所有頂點的權值都在集合{c1,c2,…,cn}中,我們的小朋友就會將其稱作神犇的。並且他認為,一棵帶點權的樹的權值,是其所有頂點權值的總和。   給出一個整數

常用資料結構與演算法:(binary heap)

一:什麼是二叉堆 二:二叉堆的實現  三:使用二叉堆的幾個例子 一:什麼是二叉堆 1.1:二叉堆簡介       二叉堆故名思議是一種特殊的堆,二叉堆具有堆的性質(父節點的鍵值總是大於或等於(小於或等於)任何一個子節點的鍵值),二叉堆又具有二叉樹的性質(二叉堆是完全二叉樹

[資料結構與演算法]-(binary heap)介紹及其實現(Java)

本文歡迎轉載,轉載前請聯絡作者。若未經允許轉載,轉載時請註明出處,謝謝! http://blog.csdn.net/colton_null 作者:喝酒不騎馬 Colton_Null from CSDN 一.什麼是二叉堆? 二叉堆(binary heap)

資料結構實現 6.2:優先佇列_基於實現(C++版)

資料結構實現 6.2:優先佇列_基於最大二叉堆實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 入隊操作 2.2 出隊操作 2.3 查詢操作 2.4 其他操作 3. 演算法複雜度分析

實驗五:樹和樹的實驗2

使用二叉樹的鏈式儲存結構,建立一棵二叉樹,進行前序、中序以及後序遍歷,同時求得二叉樹的結點個數以及葉子結點個數。 程式原始碼: # ifndef Bitree_H # define Bitree_H struct BiNode { char data; BiNode *lchi

排序,分別利用排序

#include <iostream> using namespace std; //下沉調整(本質上都是上浮調整,只不過是將最小元素上浮) void downAdjust(int array[],int parentIndex,int length) { in

1-6 統計樹度為2的結點個數 (10 分)

本題要求實現一個函式,可統計二叉樹中度為2的結點個數。 函式介面定義: int NodeCount ( BiTree T); T是二叉樹樹根指標,函式NodeCount返回二叉樹中度為2的結點個數,若樹為空,返回0。 裁判測試程式樣例: #include <stdio.

Codeforces Round #303 (Div. 2) E 短路迪傑斯特拉(實現)

連結:戳這裡 E. Paths and Trees time limit per test3 seconds memory limit per test256 megabytes inputstandard input outputstandard output

給定搜尋樹和兩個整數A,B (整數和整數)。如何刪除不在該區間內的元素(剪枝)

由於需要檢查樹中的每一個元素,結點的處理順序可以是從葉子結點到根結點。這樣當處理到結點本身時,其左子樹和右字樹為有效剪枝的BST。 static BianrySearchTreeNode PruneB

排序樹(BST) 講 【 理解 + 例題 】 更新ing ...

    很多時候會去忘記,你真正在乎的,是什麼、、、     set 就是用BST來維護集合的一個容器,書上根本沒講、、、、     定義:二叉排序樹(Binary Sort Tree)又稱二叉查詢樹(Binary Search Tree),亦稱二叉搜尋樹。 它或者是一棵空

樹的高度 java 利用遞迴和層次遍歷兩種方法

原文:http://blog.csdn.net/fangchao3652/article/details/53456468 ackage edu.lnu.fang.BiTree; import java.util.ArrayList; import java.util.L

利用棧結構實現樹的非遞迴遍歷,樹深度、葉子節點數、兩個結點的最近公共祖先及樹結點的距離

原文地址:http://blog.csdn.net/forbes_zhong/article/details/51227747 利用棧實現二叉樹的非遞迴遍歷,並求二叉樹的深度、葉子節點數、兩個節點的最近公共祖先以及二叉樹結點的最大距離,部分參考《劍指offer》這本書

[Swift]LeetCode823. 帶因子的樹 | Binary Trees With Factors

spa count () bsp factors 條件 equal reat int Given an array of unique integers, each integer is strictly greater than 1. We make a binary

模板

esp printf 最小值 namespace 記得 class queue 二叉 %d 手寫堆 可以視作是一種完全二叉樹結構 #include<iostream> #include<cstring> #include<algor

【模板】

names ret %d opened code spa ace cnblogs 一個空格 因為根的實現方法(優先隊列)默認為大根堆,即從大到小排列,所以在需要的時候需要手寫小根堆。 題目描述 如題,初始小根堆為空,我們需要支持以下3種操作: 操作1: 1 x 表示將x插入

scala寫算法-用解決topK

app unit roo ast atm mark 構建 操作 mnt topK問題是指從大量數據中獲取最大(或最小)的k個數,比如從全校學生中尋找成績最高的500名學生等等. 本問題可采用小根堆解決.思路是先把源數據中的前k個數放入堆中,然後構建堆,使其保持堆序(可以簡單

關於dijkstra的優化

eat algo 最壞情況 str 但是 lan 部分 是我 算法 YY引言 在NOI2018D1T1中出現了一些很震驚的情況,D1T1可以用最短路解決,但是大部分人都在用熟知的SPFA求解最短路。而SPFA的最壞復雜度能夠被卡到$O(VE)$。就是邊的數量乘以點的數量,

關於的看法

  最近在複習小根堆,看了好多部落格,一些思想記錄一下。   早上自己團隊在比賽的時候,第一道題爆零,老師講是用小根堆解決,所以好好複習了一下小根堆; 首先,小根堆其實就是二叉樹。當然,最出名的是一個叫做堆排序的東東,它的時間複雜度為O(nlogn)。足夠的小吧,此外它還有一個別名叫做二叉樹排序。 贈送