Skip to content

Instantly share code, notes, and snippets.

@MarkBaker
Last active Mar 31, 2016
Embed
What would you like to do?
Iterating over an SPLHeap appears to remove entries from the heap

Trying a little experiment with PHP's SPLHeap, but puzzled by the fact that iterating over the heap seems to be removing each entry as I access it.

The code

class ExtendedSPLHeap extends \SPLHeap {

    protected function compare($a, $b) {
        if ($a->latitude == $b->latitude) {
            return 0;
        }
        return ($a->latitude < $b->latitude) ? -1 : 1;
    }

}


$citiesHeap = new \ExtendedSPLHeap();

$file = new \SplFileObject("cities.csv");
$file->setFlags(SplFileObject::DROP_NEW_LINE | SplFileObject::SKIP_EMPTY);
while (!$file->eof()) {
    $cityData = $file->fgetcsv();
    if ($cityData !== NULL) {
        $city = new \StdClass;
        $city->name = $cityData[0];
        $city->latitude = $cityData[1];
        $city->longitude = $cityData[2];

        $citiesHeap->insert($city);
    }
}

echo 'There are ', $citiesHeap->count(), ' cities in the heap', PHP_EOL;

echo 'FROM NORTH TO SOUTH', PHP_EOL;
$citiesHeap->top();
while ($citiesHeap->valid()) {
    $city = $citiesHeap->current();

    echo sprintf(
        "%-20s %+3.4f  %+3.4f" . PHP_EOL,
        $city->name,
        $city->latitude,
        $city->longitude
    );

    $citiesHeap->next();
}

echo 'There are ', $citiesHeap->count(), ' cities in the heap', PHP_EOL;

and a sample of my cities.csv file

Birmingham,52.4800,-1.9100
Bristol,51.4600,-2.6000
Leeds,53.8100,-1.5500
Liverpool,53.4167,-3.0000
London,51.5171,-0.1062
Manchester,53.4800,-2.2400
Newcastle upon Tyne,54.9833,-1.5833

The output is

There are 7 cities in the heap
FROM NORTH TO SOUTH
Newcastle upon Tyne  +54.9833  -1.5833
Leeds                +53.8100  -1.5500
Manchester           +53.4800  -2.2400
Liverpool            +53.4167  -3.0000
Birmingham           +52.4800  -1.9100
London               +51.5171  -0.1062
Bristol              +51.4600  -2.6000
There are 0 cities in the heap

What puzzles me is that there are 0 entries remaining in the heap after that initial iteration over it; I'd expected that I could rewind and reiterate, but it seems my code is actually extracting the entries or otherwise removing the objects from each node of the tree as I retrieve them.


With further investigation (and help from nikic), it would appear that the next() method doesn't simply traverse the node pointers, but actually removes the current node from the heap as well.

This is not how a heap should behave, and surely adds extra overhead (the actual removal of the element and subsequent adjustment of all affected node pointers) to traversing the tree. Only the extract() method should remove nodes; and the rewind() method is rendered meaningless as a result.

Looks like it's given me my next project for core PHP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment