演算法與資料結構之索引堆

2021-09-11 12:07:34 字數 4298 閱讀 7426

前面的博文介紹了堆的實現堆的介紹,今天主要主要介紹索引堆,以及索引堆的優化。

索引堆是對堆進行了優化。

在堆中,構建堆、插入、刪除過程都需要大量的交換操作。在之前的實現中,進行交換操作是直接交換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...