前面的博文介紹了堆的實現堆的介紹,今天主要主要介紹索引堆,以及索引堆的優化。
索引堆是對堆進行了優化。
在堆中,構建堆、插入、刪除過程都需要大量的交換操作。在之前的實現中,進行交換操作是直接交換datas陣列中兩個元素。而索引堆交換的是這兩個元素的索引,而不是直接交換元素。
主要有兩個好處:
索引堆使用了乙個新的int型別的陣列,用於存放索引資訊。部分**如下:
// 屬性
$data = array();// 存放資料的陣列 datas[1..n]
$indexes = array(); // 索引陣列
複製**
這裡這個indexes陣列,存放的是什麼資訊呢?它是如何工作的呢?假如我們有這樣乙個最小堆:
那麼用陣列表示就是:
datas: [-, 1, 15, 20, 34, 7]
複製**
現在要維護最小堆的有序性,就需要交換15和7這兩個元素。交換之後的元素陣列是:
datas: [-, 1, 7, 20, 34, 15]
複製**
而此時,我們再想找到原來在datas[2]位置的元素,已經找不到了。因為此時data[2]已經換成了7,而系統並沒有記錄15被換到了什麼地方。
可不可以既保持$data的原始特性(讀取o(1))想要得到i位置的元素,直接datas[i]就可以了, 也保持堆的特性。可以的,使用索引堆。
使用索引堆後,初始化兩個陣列應該是這樣的:
$datas: [-, 1, 15, 20, 34, 7]
$indexes: [-, 1, 2, 3, 4, 5]
複製**
這個時候,我們就交換indexes陣列裡面的索引2和5,而不操作datas陣列。交換後兩個陣列是這個樣子:
$datas: [-, 1, 15, 20, 34, 7]
$indexes: [-, 1, 5, 3, 4, 2]
複製**
這個時候,想要得到i位置的元素,就需要
<?php
// require('../library/sorttesthelper.php');
require('../sortingadvance/quicksort.php');
/** * 索引堆
*/class
indexmaxheap
// public function __construct($arr)
public
function
insert
($item)
public
function
extractmax
() /**
* [extractmaxindex 讓外界感覺從0開始]
* @return [type] [description]
*/public
function
extractmaxindex
() public
function
getmaxindex
() public
function
getmax
() public
function
isempty
() public
function
getdata
() /**
* [change 修改乙個元素的值]
* @param [type] $i [description]
* @param [type] $newitem [description]
* @return [type] [description]
*/public
function
change
( $i , $newitem )}}
/*** [_shiftup 新加入到堆中的元素直接放在陣列後面,再與父元素比較後交換位置,直到根節點]
* @param [type] $k [description]
* @return [type] [description]
*/private
function
_shiftup
($k)
}/**
* [_shiftdown 元素出堆的時候,需要維護此時的堆依然是乙個大根堆, 此時將陣列元素的最後乙個值與第乙個值交換,後從上往下維護堆的性質]
* @param [type] $k [description]
* @return [type] [description]
*/private
function
_shiftdown
($k)
}}function
heapsortusingindexmaxheap
($arr, $n)
print("形成大根索引堆後, 從大大小輸出為:\n");
for( $i = $n-1 ; $i >= 0 ; $i -- )
}$n = 10;
$arr = generaterandomarray($n, 0, $n);
print_r("生成的元素陣列為:\n");
print_r( $arr);
$arr = heapsortusingindexmaxheap($arr, $n);
?>
複製**
生成的元素陣列為:
array
( [0] => 5
[1] => 7
[2] => 3
[3] => 2
[4] => 1
[5] => 6
[6] => 6
[7] => 3
[8] => 7
[9] => 9
)形成大根索引堆後, 從大大小輸出為:77
6666
5331
複製**
接著上面的case,我們現在能夠獲得類似於這樣的資料:arr排序後,第2大的數
arr[indexes[1]]
而現在有這樣乙個需求:我想知道原來arr陣列中第i個位置,排好序後在哪個位置。應該怎樣做?
常規的方法是遍歷indexes陣列,像這樣:
for( $j = 1 ; $j <= $this->count ; $j ++ )
}複製**
這個複雜度最差為o(n);
那麼有沒有什麼方法可以提高效能呢?
有,那就是再一用乙個陣列reverses,作為反向索引。反向索引存放的資料通俗來講就是這樣:
reverses[i] == j
indexes[j] == i
複製**
進而推導出:
reverses[indexes[i]] = i;
indexes[reverses[i]] = i;
複製**
看這個例子:
indexes[1] = 10; 而reverses[1]儲存的是在indexes陣列中值為10的索引1在indexes中的位置,它的值為8,有 reverses[1] = 8;代表index陣列中第8個
雖然使用反向索引提高了某些時候的查詢效率,但會使得程式變得更加複雜。因為在插入和刪除時都要維護這個陣列。
核心思想是:不管任何操作,都要維護indexes陣列和reverse陣列的性質。
像作業系統的程序管理:每次都使用堆找到優先順序最高的程序執行,如果來了新的程序只需要將其插入堆中,如果需要更改進行的優先順序,只需要使用change函式進行更改
可以將需要攻擊的敵人放入堆中,使用堆選擇最需要攻擊的敵人。如果有新的敵人進入則插入堆。
多路歸併排序
* merge的時候,將各個分割的字塊的第乙個元素形成乙個最小堆,每次取堆頂元素進行merge
* 如果n個元素進行n路歸併,其實歸併演算法就成了,堆排序演算法。
複製**
-------------------------華麗的分割線--------------------
看完的朋友可以點個喜歡/關注,您的支援是對我最大的鼓勵。
個人部落格番茄技術小棧和掘金主頁
資料結構與演算法 堆結構
1 本質 一顆特殊的樹。2 特性 3 分類 對於每乙個節點的值都大於等於子節點的值的情況,該堆被稱為大頂堆。對於每乙個節點的值都小於等於子節點的值的情況,該堆被稱為小頂堆。4 儲存方式 對於完全二叉樹而言,陣列儲存方式是最節省記憶體的。5 插入節點的時間複雜度 將節點插入到靠左的底層作為新的葉子節點...
資料結構與演算法 堆
堆 完全二叉樹,高度為o lgn 基本操作至多和樹的高度成正比,構建堆的時間複雜度是o n 堆是一顆完全二叉樹,假設有n個節點,樹高h log2 n 證明方法如下 1 假設根節點的高度為0,葉子節點高度為h,每層包含元素個數為2 x,x 從0 到h。2 構建堆的過程是自下而上,對於每層非葉子節點需要...
資料結構與演算法 堆
在 演算法設計技巧與分析 這本書的第四章,介紹了堆。於是按照上面的偽 實現了一下。資料結構定義maxheap.hpp如下,1 ifndef max heap hpp 2 define max heap hpp 34 include 5using std vector 67 class maxheap...