1. 程式人生 > >4-4 Shift Down如何從堆中取出一個元素(對應優先佇列中出隊這個操作)

4-4 Shift Down如何從堆中取出一個元素(對應優先佇列中出隊這個操作)

Shift Down 的具體操作步驟

只能取出根節點處的元素,即第 1 個元素(索引為 1)。

步驟:將最後一個元素放到第1個元素的位置,這樣做交換和移動的次數最少,並且保持了完全二叉樹的性質,但是此時並不滿足最大堆的性質。(想清楚為什麼要這麼做)

保持了完全二叉樹的性質,但是此時 完全二叉樹不滿足最大堆的性質,我們就須要將第1 個元素逐層下移來進行判斷。

具體的步驟:如果存在右孩子,就把右孩子和左孩子比較,比出最大的那個,再和自己比較,如果比自己大,就交換位置,這樣的過程直到“自己比左右兩個孩子都大”為止。

把當前元素和它的左右孩子,三個數進行比較,找出最大的,誰大跟誰換。

public
int extractElement() { int num = data[1]; assert this.count >= 0; swap(data, 1, count); this.count--; shiftDown(1); return num; }

說明:最大堆的最後一個元素是 data[count]。

/**
 * 只要有左右孩子,左右孩子只要比自己大,就交換
 *
 * @param h
 */
private void shiftDown(int h) {
    while (2 * h <= count) { // 如果這個元素有左邊的孩子
int k = 2 * h; if (k + 1 <= count && data[k + 1] > data[k]) {// 如果有右邊的孩子,大於左邊的孩子,就好像左邊的孩子不存在一樣樣 k = k + 1; } if (data[h] < data[k]) { swap(data, h, k); } h *= 2; } }

下面是我在練習的時候的一種寫法,雖然沒有問題,但是增大了判斷的次數。

圖:練習時候的一種寫法

說明:在完全二叉樹中,如何表示有孩子?結論:有左孩子就夠了。

提示:如果我們明白這個 Shift Down 的過程的話,程式碼其實可以很快地寫出來。

一定要注意:這裡的迴圈條件是 2*k <= count ,等於號不能漏掉,自己手畫一個完全二叉樹就清楚了。

優化的思路:

逐漸下移、上移的過程可以不用交換,借用插入排序優化的思路,多次賦值,一次交換。

是不是還可以用 for 迴圈來做這件事情?

下面我們進行功能測試:

@Test
public void test03() {
    int capacity = 10;
    MaxHeap maxHeap = new MaxHeap(capacity);
    Random random = new Random();
    int nextInt;
    for (int i = 0; i < capacity; i++) {
        // 得到一個 [0,99] 或者說 [0,100) 區間之內的隨機數
        nextInt = random.nextInt(100);
        maxHeap.insert(nextInt);
    }

    System.out.println(Arrays.toString(maxHeap.getData()));

    while (!maxHeap.isEmpty()) {
        int extractMax = maxHeap.extractMax();
        System.out.printf("%d ", extractMax);
    }
}

寫到這裡,我們可以直接輸出來檢驗一下,自己寫出的最大堆資料結構是否符合最大堆的性質。因為每一次從最大堆取出的總是陣列中最大的元素,所以可以將最大堆用於排序,使用排序的工具檢驗最大堆的正確性。

相關推薦

4-4 Shift Down如何取出一個元素對應優先佇列這個操作

Shift Down 的具體操作步驟 只能取出根節點處的元素,即第 1 個元素(索引為 1)。 步驟:將最後一個元素放到第1個元素的位置,這樣做交換和移動的次數最少,並且保持了完全二叉樹的性質,但是此時並不滿足最大堆的性質。(想清楚為什麼要這麼做) 保持了

java List隨機取出一個元素

n) pos () pan ext array bsp spa arr java 從List中隨機取出一個元素 1 List<Integer> list = new ArrayList<>(); 2 Random random =

java使用poi把資料庫取出的資料寫入到excel檔案並儲存到指定檔案路徑

  有時候我們要把從資料庫中取出的資料匯入到excel中,使取到的資料看起來更加的直觀和方便,在java中如何實現取到的資料匯入到excel中呢?以下就是使用poi工具吧資料寫入excel檔案中的解決方法: Excel表格副檔名有.xlsx和.xls兩種格式     &n

三個程序P1、P2、P3互斥使用一個包含N(N>0)個單元的緩衝區。P1每次用produce()生成一個正整數並用put()送入緩衝區某一空單元;P2每次用getOdd()該緩衝區取出一個奇數並

這個問題較為簡單:與生產者一消費者問題非常類似,只不過涉及的程序多了一個。因此,我們可以用類似於生產者一消費者的解決方法來解決這個問題。不過,由於本問題的範圍在生產者~消費者問題上進行了線性擴充套件

CCF-CSP201609-4 交通規劃Dijkstra+優先佇列

題目連結 問題描述 試題編號: 201609-4 試題名稱: 交通規劃 時間限制: 1.0s 記憶體限制: 256.0MB 問題描述: 問題描述   G國國王來中國參觀後,被中國的高速鐵路深深的震撼,決定為自己

jq陣列刪除指定元素根據自定義條件 超好用的 $.grep() 方法 jQuery.grep()

  轉: jQuery.grep() 什麼是jQuery.grep()?   jQuery.grep()是一個查詢滿足過濾函式的陣列元素的函式。原始陣列不受影響,返回值為陣列。 用法介紹: 寫法: jQuery.grep( array, function(elementOfArr

取出一個位元組byte的每一位bit

例:byte byZT = 0x36;int n0, n1, n2, n3, n4, n5, n6, n7;n0 = (byZT & 0x01) == 0x01 ? 1 : 0; if (n0 == 0) {textBox50.Text = "正常";} else{ 

零開始擼一個App】Fragment和導航的使用

## Fragment簡介 `Fragment`自從Android 3.0引入開始,它所承擔的角色就是顯而易見的。它之於`Activity`就如html片段之於頁面,好處無需贅述。 Fragment例項由Activity的`FragmentManager`管理,其生命週期和Activity一樣,都不是由開

訪問樹的所有元素DOM

解決 優先 一個 示例 function 函數 func 及其 target 創建一個函數,給定頁面上的DOM元素,將訪問元素本身及其所有後代(而不僅僅是它的直接子代)。對於訪問的每個元素,函數應將該元素傳遞給提供的回調函數。 函數的參數應該是: 一個DOM元素

phpunset一個變量之後, 通過引用賦值引用這個變量的變量會被unset嗎?

是否 有著 amp 如果 存在 其他 得到 val 發現 在php中變量的賦值分為按值賦值, 和引用賦值. 在按值賦值中, $a = val; $b = $a ; 可以看成$a = val; $b =val;變量b被賦予a的值之後, a和b便沒有任何的引用關系了, 此

在內網安裝軟件內網不能連接外網

-- packages /var/ 自己 配置 內容 pca ges add 一 :制作鏡像光盤 二: /etc/yum.conf 這裏配置文件需要更改 keepcache=0 ==》 keepcache=1 (這裏是更改為“1” 是讓我們保存自己安裝所需要的依

在頁面隱藏一個元素的幾種方法

osi play hid abs 隱藏 一個 bili cit eight 1.display:none,不占據空間,無法點擊; 2.visibility:hidden,占據空間,無法點擊; 3.height:0; overflow:hidden,不占據空間,無法點擊; 4

計算機網絡的基本器件網卡,集線器,交換機,路由器

模型 主機 檢測 多個 有一個 決定 拓撲 網絡信息 擁有 1.RJ45接口: RJ45是布線系統中信息插座(即通信引出端)連接器的一種,連接器由插頭(接頭、水晶頭)和插座(模塊)組成,插頭有8個凹槽和8個觸點。RJ是Registered Jack的

SQL Server字段類型對應的C#的數據類型

整數 bsp 精度 機會 tiny adding border real p值 數據庫 C#程序 int int32 text string bigint int64 binary System.Byte[]

jquery如何刪除陣列一個元素

jquery刪除陣列中的一個元素的方法是用 splice 實現的。 舉例說明: var arrList = ['a','b','c','d']; arrList.splice(jQuery.inArray('b',arrList),1); alert(arrList); 其中j

插入一個元素到有序順序表,使其再次有序

程式碼: #include <stdio.h> /* 題目:資料結構題集17頁2.11 設順序表中資料元素遞增有序,試寫一演算法,將x插入到順序表的適當位置上,以保持該表的有序性 演算法:逆序遍歷順序表找合適的插入new_elem的位置,並將其插入 */ #define maxl

spring bean的單例和多例的使用場景和在單例bean注入多例不看後悔,一看必懂

為什麼用單例或者多例?何時用? 之所以用單例,是因為沒必要每個請求都新建一個物件,這樣子既浪費CPU又浪費記憶體; 之所以用多例,是為了防止併發問題;即一個請求改變了物件的狀態,此時物件又處理另一個請求,而之前請求對物件狀態的改變導致了物件對另一個請求做了錯誤的處理;  

如何刪除陣列一個元素

第一種:刪除陣列中指定位置的元素: 方法一: import java.util.Arrays; import java.util.Scanner; public class test { public static void main(String[] args) { int

如何判斷一個元素在億級資料是否存在?

前言 最近有朋友問我這麼一個面試題目: 現在有一個非常龐大的資料,假設全是 int 型別。現在我給你一個數,你需要告訴我它是否存在其中(儘量高效)。 需求其實很清晰,只是要判斷一個數據是否存在即可。 但這裡有一個比較重要的前提:非常龐大的資料。 常規實現 先不考慮這個條件,我們腦海中

WPF:只讀集合在 XAML 的繫結WPF:Binding for readonly collection in xaml

問題背景: 某一天,我想做一個簽到打卡的日曆。基於 Calendar,想實現這個目標,於是找到了它的 SelectedDates 屬性,用於標記簽到過的日期。 那麼 問題 來了: 基於MVVM模式,想將其在xaml中繫結到ViewModel中的一個List<DateTime&g