php實現堆排序演算法
阿新 • • 發佈:2018-12-31
最近在準備各種面試,複習了一波演算法基礎,關於什麼是堆排序我就不多說了,這裡說的很詳細,不明白的可以參考一下:
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: 堆排序 */ //節點類 classNode{ 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右 } } //測試堆排序類 classATest{ 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小白可能比較懵,大神可能也不屑,哈哈哈