class Heap
{
    public $deep = 0;
    public $data = [];

    public function push($value)
    {
        $deepStartIndex = pow(2, $this->deep) - 1;
        $nextDeepStartIndex = $deepStartIndex + pow(2, $this->deep);
        array_push($this->data, $value);
        $lastIndex = array_key_last($this->data);
        if ($lastIndex == $nextDeepStartIndex) {
            $this->deep++;
        }
        $this->swapUp($lastIndex);
    }

    public function pop()
    {

        if (!isset($this->data[0])) {
            return null;
        }

        $min = $this->data[0];

        $lastIndex = array_key_last($this->data);
        $this->data[0] = $this->data[$lastIndex];
        unset($this->data[$lastIndex]);

        $deepStartIndex = pow(2, $this->deep) - 1;
        if ($deepStartIndex == 0) {
            return $min;
        }

        if ($lastIndex == $deepStartIndex) {
            $this->deep--;
        }

        $this->swapDown(0);

        return $min;
    }

    private function swapDown($index)
    {
        while (true) {
            $leftIndex = 2 * $index + 1;
            $rightIndex = 2 * $index + 2;

            $leftValue = !isset($this->data[$leftIndex]) ? $this->data[$index] + 1 : $this->data[$leftIndex];
            $rightValue = !isset($this->data[$rightIndex]) ? $this->data[$index] + 1 : $this->data[$rightIndex];

            if ($this->data[$index] <= $leftValue && $this->data[$index] <= $rightValue) {
                break;
            }

            $minIndex = $leftValue <= $rightValue ? $leftIndex : $rightIndex;

            $temp = $this->data[$index];
            $this->data[$index] = $this->data[$minIndex];
            $this->data[$minIndex] = $temp;
            $index = $minIndex;

        }
    }

    private function swapUp($index)
    {
        while (true) {

            if ($index == 0) {
                break;
            } else {
                if ($index % 2 == 0) {
                    $parentIndex = $index / 2 - 1;
                } else {
                    $parentIndex = floor($index / 2);
                }
            }

            if ($this->data[$parentIndex] > $this->data[$index]) {
                $temp = $this->data[$index];
                $this->data[$index] = $this->data[$parentIndex];
                $this->data[$parentIndex] = $temp;
                $index = $parentIndex;
            } else {
                break;
            }

        }
    }
}

results matching ""

    No results matching ""