1. 程式人生 > >資料結構--堆的實現(下)

資料結構--堆的實現(下)

1,堆作為優先順序佇列的應用

對於普通佇列而言,具有的性質為FIFO,只要實現在隊頭刪除元素,在隊尾插入元素即可。因此,這種佇列的優先順序可視為按 時間到達 的順序來衡量優先順序的。到達得越早,優先順序越高,就優先出佇列被排程。

更一般地,元素 不能單純地按時間到來的先後來分優先順序(或者說插入的順序),在這種情形下,使用堆更容易表達優先順序佇列。

Sometimes the processing order of the items in a queue needs to be based on characteristics of those items,
rather than just the order they are created or added to the queue.

2,堆的兩個性質:①結構性質--堆從結構上看是一顆完全二叉樹。然而,從物理儲存上看,堆的實現基本上是使用一個一維陣列儲存堆中所有的結點。②ordering property---這是由堆的定義決定的,如大頂堆:根結點的值要大於左右孩子的值。

由於堆具有這兩個性質,故在對堆進行操作時,如插入操作、刪除操作……都需要維護好這兩個性質,因此:這也是為什麼堆的插入、刪除操作經常需要進行向上調整和向下調整,這就是為了維護堆的 ordering property。

3,建堆時間複雜度的分析

資料結構--堆的實現(上)中,分析了建堆的兩種方法,時間複雜度一種為O(nlogn),一種為O(n)。現在仔細分析如下:

 1 import java.io.File;
 2 import java.io.FileNotFoundException;
 3 import java.util.Scanner;
 4 
 5 public class Sort {
 6     public static void main(String[] args) throws FileNotFoundException{
 7         Scanner sc = new Scanner(new File("inputfile"));//read heap's element from inputfile
8 int n = sc.nextInt();//first line in the file gives number of integers to be read 9 ArrayMaxHeap<Integer> sortHeap = new ArrayMaxHeap<Integer>(n); 10 //build heap 11 for(int i = 0; i < n; i++) 12 sortHeap.add(sc.nextInt());//O(nlogn) 13 14 //sort phase 15 while(!sortHeap.isEmpty()) 16 System.out.println(sortHeap.removeMax()); 17 } 18 }

在上面for迴圈中的建堆操作中,新增堆中的第一個元素時,完全二叉樹高度為1,呼叫add方法進行堆調整的最壞情況需要 Log1 時間。新增第二個元素時,完全二叉樹高度為2,進行堆調整的最壞情況需要 log2 時間……新增第 i 個元素時,最壞需要 logi 時間進行堆調整。故將 n 個元素新增到堆中需要時間:

log1 + log2 + log3 + …… + log(n-1) + logn = log(1*2*3……*n) = log n!

n! = (n/e)nsqrt(2n*pi)

故 O(logn!) = O(nlogn)

同理,也可分析下 while 迴圈中的堆排序。removeMax()的時間複雜度為logn,n為當前堆中元素的個數。故堆排序的時間複雜度為O(nlogn)

從這裡可以看出,此種建堆的方法是呼叫堆定義的介面來實現的。即呼叫 堆的介面add()來實現。

另一種建堆的方式則是直接操作堆的底層儲存---一維陣列 來建堆。此方法建堆的時間複雜度為O(n)

 1 Integer[] arr = new Integer[4];arr[0] = 20;arr[1] = 40;arr[2] = 30;arr[3] = 10;
 2 ArrayMaxHeap<Integer> heap2 = new ArrayMaxHeap<Integer>(arr);
 3 
 4 public ArrayMaxHeap(T[] entries){
 5         heap = (T[]) new Comparable[entries.length + 1];//how to use generic array...
 6         lastIndex = entries.length;
 7         for(int index = 0; index < entries.length; index++)
 8         {
 9             heap[index + 1] = entries[index];//第0號位置不存放元素
10             System.out.println(heap[index + 1]);
11         }
12         for(int index = lastIndex / 2; index >= 1; index--)
13             reheap(index);//從最後一個非葉結點到根結點呼叫reheap進行堆調整操作
14     }

在第12行的for迴圈中,從最後一個非葉結點(lastIndex/2)開始,直接呼叫reheap()操作Integer陣列。

private void reheap(int rootIndex){
        boolean done = false;//標記堆調整是否完成
        T orphan = heap[rootIndex];
        int largeChildIndex = 2 * rootIndex;//預設左孩子的值較大
        //堆調整基於以largeChildIndex為根的子樹進行
        while(!done && (largeChildIndex <= lastIndex)){
            //largeChildIndex 標記rootIndex的左右孩子中較大的孩子
            int leftChildIndex = largeChildIndex;//預設左孩子的值較大
            int rightChildIndex = leftChildIndex + 1;
            //右孩子也存在,比較左右孩子
            if(rightChildIndex <= lastIndex && (heap[largeChildIndex].compareTo(heap[rightChildIndex] )< 0))
                largeChildIndex = rightChildIndex;
            if(orphan.compareTo(heap[largeChildIndex]) < 0){
                heap[rootIndex] = heap[largeChildIndex];
                rootIndex = largeChildIndex;
                largeChildIndex = 2 * rootIndex;//總是預設左孩子的值較大
            }
            else//以rootIndex為根的子樹已經構成堆了
                done = true;
        }
        heap[rootIndex] = orphan;
    }

reheap的虛擬碼如下:

input:array A[0...n-1]
output: max heap in A[0...n-1]

x = n/2 - 1
while(x>=0)
    v=value at x
    siftdown(v)
    x=x-1
endwhile

時間複雜度為O(n)的分析:

假設堆的高度為 h,當reheap某個結點時,需要對 以該結點為根 的子樹進行向下的調整。向下調整時根結點有兩次比較(與左右孩子的比較)。

因此,假設某結點在第 i 層,0<= i <h,該結點一共需要 2(h-i)次比較。(最後一層葉結點是不需要比較的,因為建堆是從非葉結點開始)

由於是完全二叉樹,故第 i 層的結點個數為 2i

總比較次數為:除去最後一層葉子結點外,其它層的所有的結點的比較次數之和.設總比較次數為S

因此,終於明白這種建堆方法的時間複雜度為O(n)了。

相關推薦

資料結構-實現優先佇列(java)

佇列的特點是先進先出。通常都把佇列比喻成排隊買東西,大家都很守秩序,先排隊的人就先買東西。但是優先佇列有所不同,它不遵循先進先出的規則,而是根據佇列中元素的優先權,優先權最大的先被取出。這就很像堆的特徵:總是移除優先順序最高的根節點。 重點:優先順序佇列,是要看優先順序的,

資料結構--實現()

1,堆作為優先順序佇列的應用 對於普通佇列而言,具有的性質為FIFO,只要實現在隊頭刪除元素,在隊尾插入元素即可。因此,這種佇列的優先順序可視為按 時間到達 的順序來衡量優先順序的。到達得越早,優先順序越高,就優先出佇列被排程。 更一般地,元素 不能單純地按時間到來的先後來分優先順序(或者說插入的順序),

的python實現及其應用 資料結構--實現之深入分析

堆的概念 優先佇列(priority queue)是一種特殊的佇列,取出元素的順序是按照元素的優先權(關鍵字)大小,而不是進入佇列的順序,堆就是一種優先佇列的實現。堆一般是由陣列實現的,邏輯上堆可以被看做一個完全二叉樹(除底層元素外是完全充滿的,且底層元素是從左到右排列的)。 堆分為最大堆和最小堆,最大堆

資料結構&&heap&priority_queue&實現

目錄 什麼是堆? 大根堆 小根堆 堆的操作 什麼是堆? 堆是一種資料結構,可以用來實現優先佇列 大根堆 大根堆,顧名思義就是根節點最大。我們先用小根堆的建堆過程學習堆的思想。 小根堆 下圖為小根堆建堆過程 堆的操作 上浮 下沉 插入 彈出 取頂 堆排序 STL heap 所在庫 #include

資料結構--實現之深入分析

一,介紹 以前在學習堆時,寫了兩篇文章:資料結構--堆的實現(上)   和   資料結構--堆的實現(下),  感覺對堆的認識還是不夠。本文主要分析資料結構 堆(討論小頂堆)的基本操作的一些細節,比如 insert(插入)操作 和 deleteMin(刪除堆頂元素)操作的實現細節、分析建堆的時間複雜度、堆的

資料結構--實現(上)

1,堆是什麼? 堆的邏輯結構是一顆完全二叉樹,但物理結構是順序表(一維陣列)。同時,此處的堆不要與JAVA記憶體分配中的堆記憶體混淆。這裡討論的是資料結構中的堆。 2,陣列實現堆的優勢及特點 由於堆從邏輯上看是一顆完全二叉樹,因此可以按照層序遍歷的順序將元素放入一維陣列中。注意為了方便,陣列的元素存

資料結構實現以及的面試題

堆 堆的特點 堆有大堆和小堆之分 小堆: ①任意結點的關鍵碼均小於等於他的左右孩子的關鍵碼 ②位於堆頂的結點的關鍵碼最小 ③從根結點到每個結點的路徑上陣列元素組成的序列都是遞增的 大堆: ①任意結點的關鍵碼均大於等於他的左右孩子的關鍵碼

資料結構Java實現(6/11)(二叉&優先佇列)

堆其實也是樹結構(或者說基於樹結構),一般可以用堆實現優先佇列。 二叉堆 堆可以用於實現其他高層資料結構,比如優先佇列 而要實現一個堆,可以藉助二叉樹,其實現稱為: 二叉堆 (使用二叉樹表示的堆)。 但是二叉堆,需要滿足一些特殊性質: 其一、二叉堆一定是一棵完全二叉樹 (完全二叉樹可以用陣列表示,見下面)

使用C#實現資料結構

一、 堆的介紹:   堆是用來排序的,通常是一個可以被看做一棵樹的陣列物件。堆滿足已下特性:   1. 堆中某個節點的值總是不大於或不小於其父節點的值   任意節點的值小於(或大於)它的所有後裔,所以最小元(或最大元)在堆的根節點上(堆序性)。堆有大根堆和小根堆,將根節點最大的堆叫做最大堆或大根堆,根節點最小

redis 系列6 資料結構之字典()

一.概述   接著上篇繼續,這篇把資料結構之字典學習完, 這篇知識點包括:雜湊演算法,解決鍵衝突, rehash , 漸進式rehash,字典API。   1.1 雜湊演算法     當一個新的鍵值對 需要新增到字典裡面時,程式需要先根據“鍵值對”的鍵計算出雜湊值和索引值,再根據索引值,將包含新“鍵值對

20172310 2017-2018《程式設計與資料結構》()第八週學習總結

20172310 2017-2018《程式設計與資料結構》(下)第八週學習總結 教材學習內容總結 1.1、堆 堆(heap):是具有兩個附加屬性的二叉樹。一是堆是一顆完全樹(如果一棵二叉樹是平衡的,即所有葉子都位於h或h-1層,其中h為log2n, 且n是樹中的元素數目,且所有h層中的葉子都位於該

20172310 2017-2018《程式設計與資料結構》()第五週學習總結

20172310 2017-2018《程式設計與資料結構》(下)第五週學習總結 教材學習內容總結 第九章_排序與查詢 學習幾種排序演算法,並討論這些演算法的複雜度 9.1查詢(線性查詢與二分查詢演算法) 查詢(searching) 是在某個專案組中尋找某一指定目標元素, 或者確定該組中並不存在

20172310《程式設計與資料結構》()實驗二:二叉樹實驗報告

20172310《程式設計與資料結構》(下)實驗二:二叉樹實驗報告 報告封面 課程:《軟體結構與資料結構》 班級: 1723 姓名: 仇夏 學號:20172310 實驗教師:王志強老師 實驗日期:2018年11月3日-2018年11月9日 必修選修: 必修 實驗二-1-

基本資料結構――的基本概念及其操作

     轉載自:https://www.cnblogs.com/JVxie/p/4859889.html,同時感謝大佬的分析       在我剛聽到堆這個名詞的時候,我認為它是一堆東西的集合       但其實吧它是利用

20172310 2017-2018《程式設計與資料結構》()第九周學習總結

20172310 2017-2018《程式設計與資料結構》(下)第九周學習總結 教材學習內容總結 這一章又要學習一個新的體系了——圖 無向圖、有向圖和網路 接下來的例子都是使用這兩個圖 一些共同的基礎概念: 頂點:結點,一般用名字和標籤來表示,如A、B等。 邊:節點之間的連線,用結點對

關於資料結構 棧 樹 以及記憶體分配中的

在現如今的教材中 關於棧,堆,樹等概念比較模糊 正確的解釋如下 棧是一種資料表 操作滿足先進後出(類似木桶) 【標準解釋:只能從表的固定一端對資料進行插入與刪除操作,另一端封死。開頭的一端為棧頂,封死的一端為棧底】 樹: 樹的邏輯結構:樹中任何結點都可以有零個或多個直接後繼節點,但至

資料結構實現一個棧要求實現Push(出棧)Pop(入棧)Min(返回最小值)的時間 複雜度為O(1)

文章目錄 思路 MinStack.h MinStack.c Test.c 棧的基本實現: https://blog.csdn.net/weixin_41892460/article/details/8297385

資料結構————(TopK、

堆是資料結構的一種,可用於排序和海量資料處理中的TopK問題 堆的邏輯結構:是一顆完全二叉樹,由於是是一顆完全二叉樹我們就可通過陣列來實現他的儲存方式。 上面是一顆完全二叉樹,分別為樹狀儲存、陣列儲存。 堆的性質: 1.堆分為大堆和小堆。 2.大堆的對頂大於它的左子樹和右子樹(小堆相

Java HashMap涉及的資料結構實現

提供的功能 基於雜湊表實現的Map; 非執行緒安全的Map實現; 鍵和值都可以為null(因為有處理null的情形); 基本操作get()和put()的時間消耗是固定的; 資料儲存結構會隨著HashMap的數量而變換成不同的資料結構。 涉及到的概念 預設初始化容量 最大容量 預設的負載係數(load f

C# 利用執行緒安全資料結構BlockingCollection實現多執行緒

using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; using Danny.Infrastructure.Helper; names