php實現堆排序算法

最近在準備各種面試,複習了一波算法基礎,關於什麼是堆排序我就不多說了,這裏說的很詳細,不明白的可以參考一下:

https://jingyan.baidu.com/article/5225f26b057d5de6fa0908f3.html

廢話不多說,貼完整代碼:

<?php
/**
 * Created by PhpStorm.
 * User: KeenSting
 * Date: 2017/12/7
 * Time: 下午5:47
 * Name: 樑小蒼
 * Phone: 13126734215
 * QQ: 707719848
 * File Description: 堆排序
 */

//節點類
class Node{
    public $value;  //節點值
    public $left; //左子節點
    public $right; //右子節點
    public $father; //父節點
    public $pos_in_father; //在父節點的位置,左還是右

    public function __construct($num)
    {
        $this->value = $num;
        $this->left = $this->right = $this->father = null;
        $this->pos_in_father = null;//1 左,2右
    }
}

//測試堆排序類
class ATest{
    private $list; //存放節點列表,節點間的關係用引用表示
    private $num;  //節點數
    private $result; //結果集
    public function __construct(array $data)
    {
        $this->list = $this->result = [];
        $this->num = count($data);
        $this->createHeap($data,$this->num);
        $this->initHeap();
    }

    //執行排序
    public function run()
    {
        //交換堆頂和堆尾的節點值,移除尾部節點,加入到輸出中
        while(true)
        {
            $size = count($this->list);
            if($size>2)
            {
                array_push($this->result,$this->list[0]->value);//堆頂的數加入結果集
                $tail = array_pop($this->list);
                $this->list[0]->value = $tail->value;//堆尾的數放到堆頂,在此調整
                if($father = &$tail->father)//釋放尾部節點,修改父節點中子節點信息,置null
                {
                    if($tail->pos_in_father==1)
                        $father->left = null;
                    else
                        $father->right = null;
                }
                unset($tail);
                $this->nodeAdjust($this->list[0]);
                
            }else//只有兩個元素的時候就釋放掉
            {
                array_push($this->result,$this->list[0]->value);
                array_push($this->result,$this->list[1]->value);
                unset($this->list);
                break;
            }
        }
        //打印降序結果
        print_r($this->result);
        //打印升序結果
        print_r(array_reverse($this->result));
    }
    
    //創建堆結構,結果存放在list中,按從上到下,從左到右排列
    private function createHeap($data,$length)
    {
        //使用array_shift作爲隊列輸出
        $root = new Node($data[0]);
        $queue = [];
        $index = 0;
        array_push($queue,$root);

        while($queue)
        {
            $father = array_shift($queue);
            $index++;
            if($index<$length)//創建左節點
            {
                $node1 = new Node($data[$index]);
                $father->left = $node1;
                $node1->father = $father;
                $node1->pos_in_father = 1;
                array_push($queue,$node1);
                $index++;
            }
            if($index<$length)//創建右節點
            {
                $node2 = new Node($data[$index]);
                $father->right = $node2;
                $node2->father = $father;
                $node2->pos_in_father = 2;
                array_push($queue,$node2);
            }

            array_push($this->list,$father);

        }

    }

    //初始化爲大頂堆
    private function initHeap()
    {
        for($i=$this->num-1;$i>=0;$i--)
        {
            $tmp = &$this->list[$i];
            $this->nodeAdjust($tmp);
        }
    }

    //遞歸調整節點以及其子節點,保證大頂堆的特性
    private function nodeAdjust(&$tmp)
    {
        if(($left = &$tmp->left)!=null)//左子樹
        {
            if(($right = &$tmp->right)!=null)//右子樹在
            {

                if($right->value > $left->value)//先比較子節點大小
                {
                    if($tmp->value < $right->value)//父節點和右節點交換
                    {
                        $tmp_val = $right->value;
                        $right->value = $tmp->value;
                        $tmp->value = $tmp_val;
                        $this->nodeAdjust($right);
                    }
                }else
                {
                    if($tmp->value < $left->value)//父節點和左節點交換
                    {
                        $tmp_val = $left->value;
                        $left->value = $tmp->value;
                        $tmp->value = $tmp_val;
                        $this->nodeAdjust($left);
                    }
                }
            }else{//沒有右子樹

                if($tmp->value < $left->value)
                {

                    $tmp_val = $left->value;
                    $left->value = $tmp->value;
                    $tmp->value = $tmp_val;
                    $this->nodeAdjust($left);
                }
            }
        }else
            echo '不存在子樹----';

    }
}

$a = new ATest([3,1,9,2,7,6,11,5,4,13]);
$a->run();

執行結果如下:

Array

(

    [0] => 13

    [1] => 11

    [2] => 9

    [3] => 7

    [4] => 6

    [5] => 5

    [6] => 4

    [7] => 3

    [8] => 2

    [9] => 1

)

Array

(

    [0] => 1

    [1] => 2

    [2] => 3

    [3] => 4

    [4] => 5

    [5] => 6

    [6] => 7

    [7] => 9

    [8] => 11

    [9] => 13

)


程序主要思想如下:

1將給定待排序的數組初始化爲節點

2初始化節點,滿足大頂堆特點

3最後一個節點的值給到root節點,原來root節點的值輸出,釋放最後一個節點

4循環執行2,3,直到沒有節點可以輸出


該方法得到的是降序的排列結果,可以通過array_reverse轉換爲升序排列

程序裏面有很多引用,php小白可能比較懵,大神可能也不屑,哈哈哈

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章