自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

從二叉堆進階到堆排序與優(yōu)先隊列,前端大佬都這樣學(xué)...

開發(fā) 前端
當(dāng)遇到二叉堆的時候,我們應(yīng)該學(xué)會如何構(gòu)建一個大根堆(小根堆),這個時候就涉及到加堆和減堆的過程,下面讓從加堆和減堆開始,從而使我們能夠絲滑般的了解整個二叉堆的構(gòu)建過程。

一、二叉堆分類

二叉堆根據(jù)排序不同可分為大根堆和小根堆。

大根堆

在是完全二叉樹的前提下,其節(jié)點值大于其左右子節(jié)點值,稱為大根堆。在大根堆中根節(jié)點是所有堆節(jié)點中的最大值。

小根堆

在是完全二叉樹的前提下,其節(jié)點值小于其左右子節(jié)點值,稱為小根堆。在小根堆中根節(jié)點是所有堆節(jié)點中的最小值。

二、二叉堆的存儲

上述闡述了二叉堆其實就是一棵完全二叉樹,然后數(shù)據(jù)滿足某些特性,那么在編程中應(yīng)該如何存儲這些數(shù)據(jù)呢?這些數(shù)據(jù)間滿足那些關(guān)系呢?

1.以數(shù)組結(jié)構(gòu)存儲二叉堆

在編程中我們會以數(shù)組存儲二叉堆,以上述的最大堆為例,存儲到數(shù)組中為如下結(jié)構(gòu):

2.二叉堆中父子節(jié)點間滿足何種關(guān)系

既然數(shù)據(jù)將存儲到數(shù)組中,那么就必須知道父子節(jié)點之間的關(guān)系,即:

(1)在知道父節(jié)點的索引的時候必須找到其對應(yīng)的子節(jié)點;

(2)在知道子節(jié)點的索引的時候找到其對應(yīng)的父節(jié)點;

如下的二叉堆,設(shè)置其根節(jié)點索引為0,然后依次遞增:

已知某節(jié)點的索引為i,則其左右子節(jié)點索引為:

  • 左節(jié)點索引 = 2 * i + 1
  • 右節(jié)點索引 = 左節(jié)點索引 + 1

已知某節(jié)點的索引為i,則其父節(jié)點索引為:

  • 父節(jié)點 = parseInt((i - 1) / 2)

三、堆的基本操作

當(dāng)遇到二叉堆的時候,我們應(yīng)該學(xué)會如何構(gòu)建一個大根堆(小根堆),這個時候就涉及到加堆和減堆的過程,下面讓從加堆和減堆開始,從而使我們能夠絲滑般的了解整個二叉堆的構(gòu)建過程。(注:下面的例子以大根堆為例)

// 注:此處是封裝的交換數(shù)組中元素的方法
// 數(shù)組中交換數(shù)據(jù)
function swap(arr, i, j) {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}

1.加堆

加堆的過程實際上就是再往堆里面加入一個新的元素,然后維護該堆結(jié)構(gòu)的過程,實際上就是在數(shù)組尾部加入一個元素,然后通過不斷上浮,使其又調(diào)整為二叉堆結(jié)構(gòu)的過程。


// 大根堆加堆過程中
function heapInsert(arr, index) {
// 比較當(dāng)前位置和其父位置,若大于其父位置,則進行交換,并將索引移動到其父位置進行循環(huán),否則跳過
// 結(jié)束條件是比其父位置小或者到達根節(jié)點處
while (index > 0 && arr[index] > arr[parseInt((index - 1) / 2)]) {
swap(arr, index, parseInt((index - 1) / 2));
index = parseInt((index - 1) / 2);
}

return arr;
}

有了加堆的過程,很容易我們就可以實現(xiàn)創(chuàng)建二叉堆,如下所示:

// 創(chuàng)建二叉堆
function createBigTopHeap(arr) {
for (let i = 0; i < arr.length; i++) {
arr = heapInsert(arr, i);
}

return arr;
}


const arr = [1, 5, 9, 10, 8, 12];

console.log(createBigTopHeap(arr)); // [ 12, 9, 10, 1, 8, 5 ]

2.減堆

減堆的過程就是將堆頂元素A和最后元素B交換,然后刪除A元素并將B元素調(diào)整到合適的位置的過程,實際上就是將堆頂數(shù)據(jù)交換后,下沉數(shù)據(jù)的過程

// 減堆過程
// size指的是這個數(shù)組前多少個數(shù)構(gòu)成一個堆
// 如果想把堆頂彈出,則把堆頂和最后一個數(shù)交換,把size減1,然后從0位置經(jīng)歷一次heapify,調(diào)整一下,剩余部分變成大頂堆
function heapify(arr, index, size) {
// 獲取其左節(jié)點索引
let left = 2 * index + 1;
while (left < size) {
// 判斷一下左右子節(jié)點哪個值最大,獲取其最大值
let largest = (left + 1 < size && arr[left] < arr[left + 1]) ? left + 1 : left;
// 判斷左右子節(jié)點最大值與當(dāng)前要比較的節(jié)點哪個大
largest = arr[index] > arr[largest] ? index : largest;

// 如果最大值索引和傳進來的索引一樣,則該值到達指定位置,直接結(jié)束循環(huán)
if (index === largest) {
break;
}

// 進行交換,改變索引及其左子節(jié)點
swap(arr, index, largest);
index = largest;
left = 2 * index + 1;
}

return arr;
}

const arr = [1, 5, 9, 10, 8, 12];

console.log(createBigTopHeap(arr));

// 交換堆頂數(shù)據(jù)與最后位置數(shù)據(jù)
swap(arr, 0, arr.length - 1);

// 通過下沉的方式獲取新的堆結(jié)果
console.log(heapify(arr, 0, arr.length - 1));

四、叉堆的用途

因為二叉堆能夠高效的找出最大值和最小值,所以可用于堆排序和構(gòu)建優(yōu)先隊列。

1.堆排序

堆排序是常見的一種排序算法,整個堆排序過程如下所示:

  • 讓數(shù)組變成大根堆
  • 把最后一個位置和堆頂交換。
  • 則最大值在最后,則剩余部分做heapify,則重新調(diào)整為大根堆,則堆頂位置和該部分最后位置做交換。
  • 重復(fù)進行,直到減完,則這樣最后就調(diào)整完畢,整個數(shù)組排完序(為一個升序)
function heapSort(arr) {
if (arr === null || arr.length === 0) {
return [];
}

// 首先創(chuàng)建大根堆
for (let i = 0; i < arr.length; i++) {
arr = heapInsert(arr, i);
}

let size = arr.length; // 這個值用來指定多少個數(shù)組構(gòu)成堆

// 由于當(dāng)前已經(jīng)是大根堆,所以直接交換
swap(arr, 0, --size);

while (size > 0) {
// 重新變成大頂堆
heapify(arr, 0, size);
// 進行交換
swap(arr, 0, --size);
}

return arr;
}

const arr = [1, 5, 9, 10, 8, 12];

console.log(heapSort(arr)); // [ 1, 5, 8, 9, 10, 12

2.優(yōu)先隊列

普通的隊列是一種先進先出的數(shù)據(jù)結(jié)構(gòu),元素在隊列尾追加,而從隊列頭刪除。在優(yōu)先隊列中,元素被賦予優(yōu)先級。當(dāng)訪問元素時,具有最高優(yōu)先級的元素最先刪除。優(yōu)先隊列具有最高級先出 (first in, largest out)的行為特征。通常采用堆數(shù)據(jù)結(jié)構(gòu)來實現(xiàn)。

優(yōu)先隊列的插入

優(yōu)先隊列中元素的插入就是上述heapInsert過程,通過將元素添加到數(shù)組末尾,然后通過上浮的方式將內(nèi)容插入到合適位置。

優(yōu)先隊列中元素的刪除

優(yōu)先隊列中元素的刪除就是將根節(jié)點的元素與最后元素交換,然后將交換后的根節(jié)點下沉,調(diào)整到合適位置,重新構(gòu)成二叉堆。

責(zé)任編輯:武曉燕 來源: 前端點線面
相關(guān)推薦

2011-12-02 10:58:06

數(shù)據(jù)結(jié)構(gòu)Java

2025-04-29 09:56:39

Python數(shù)據(jù)結(jié)構(gòu)開發(fā)

2020-08-31 07:43:58

二叉堆大頂堆存儲

2023-04-06 07:39:48

2021-03-02 10:57:39

二叉樹二叉堆節(jié)點

2021-05-06 05:29:32

二叉堆數(shù)據(jù)結(jié)構(gòu)算法

2022-09-05 08:06:49

數(shù)據(jù)結(jié)構(gòu)Java

2020-11-23 08:53:34

堆Heap

2020-03-06 16:08:46

堆結(jié)構(gòu)堆排序應(yīng)用

2021-01-13 09:23:23

優(yōu)先隊列React二叉堆

2020-11-24 09:04:55

PriorityBlo

2020-09-23 18:25:40

算法二叉樹多叉樹

2022-12-26 00:51:33

雙向鏈表二叉搜索樹

2020-10-18 17:09:14

前端開發(fā)技術(shù)

2021-03-29 10:13:47

Java編程數(shù)據(jù)結(jié)構(gòu)算法

2020-12-22 08:56:51

JavaScript數(shù)據(jù)結(jié)構(gòu)前端

2020-04-27 07:05:58

二叉樹左子樹右子樹

2023-09-19 23:07:53

Python算法

2014-10-30 15:59:10

2024-07-29 11:21:24

點贊
收藏

51CTO技術(shù)棧公眾號