二叉堆binary heap(2)小根堆を利用して最大top kを求める
9359 ワード
操作を迅速に実行する性質は、スタック順序性である.最小要素を迅速に見つけたいので、最小要素は根元にあるはずです.
同様に、maxスタックを宣言し、最大メタを見つけて削除することができます.
1つのスタックでは、各ノードXについて、Xのparentのキーワード<=Xのキーワードは、ルートノードを除く(parentはない).
* Heap/BinMinHeap.php
* Heap/TopK.php
* util/Comparator.php
* autoload.php
* index.php
* 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
同様に、maxスタックを宣言し、最大メタを見つけて削除することができます.
1つのスタックでは、各ノードXについて、Xのparentのキーワード<=Xのキーワードは、ルートノードを除く(parentはない).
* Heap/BinMinHeap.php
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
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
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
* index.php
'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