最大堆:是指在一顆完全二叉樹中,一個結點的關鍵值都不小於其兒子結點的關鍵字值,既滿足(parent.value>=parent->left_child.value&&parent.value>=parent->right_child.value.).
最小堆:是指在一顆完全二叉樹中,一個結點的關鍵值都不大於其兒子結點的關鍵字值,既滿足(parent->left_child.value>=parent.value&&parent->right_child.value=>parent.value).
引入一個話題,在優先級調度隊列中,由於經常涉及刪除和插入操作,故插入和刪除的時間複雜度是影響其調度性能重要因素,但堆在優先級調度隊列中卻是一種很受歡迎的存儲表示方式,在存儲方式,數組,鏈表都可以實現優先級調度隊列,但只有堆在插入或刪除操作都能在O(
存儲表示 | 插入操作 | 刪除操作 |
---|---|---|
無序數組 | O(1) | O(N) |
無序單向鏈表 | O(1) | O(N) |
有序數組 | O(N) | O(1) |
有序單向鏈表 | O(N) | O(1) |
最大堆 | O( |
O( |
初始化最大堆或最小堆,都是從一個初始化的二叉樹中的最後一個非葉子結點繼續調整,如果是最大堆,讓最後一個非葉子結點跟其兩個兒子比較,找到最大的那個結點,然後使其最大結點作爲父結點,如果父結點有跟子結點有交換過,還有讓其子結點繼續作比較來調整直到滿足堆條件或到了最後一個結點,否則該結點調整完畢,然後再從最靠後的第二個非葉子結點做同樣的比較,挑選最大結點作爲父結點,直到滿足堆條件或到了最後一個結點,最小堆類似,但是讓最後一個非葉子結點跟其兩個兒子比較,找到最小的那個結點,然後使其最小結點作爲父結點,如果父結點有跟子結點有交換過,還有讓其子結點繼續作比較來調整直到滿足堆條件或到了最後一個結點,否則該結點調整完畢,然後再從最靠後的第二個非葉子結點做同樣的比較,挑選最小結點作爲父結點,直到滿足堆條件或到了最後一個結點,時間複雜度O(n).
就初始建立一個最大堆爲例,整個調整過程如圖:
代碼實現:
/**
注意:堆數據初始的數組的元素
索引是從1開始,而不是從0開始
故一個結點索引爲i的元素,其左
結點的索引爲2*i,右結點的索引爲
2*i+1
*/
#include <iostream>
#include<stdlib.h>
#include<stdio.h>
#define MAX_ELEMENTS 200
#define HEAP_FULL(n) (n==MAX_ELEMENTS-1)
#define HEAP_EMPTY(n) (!n)
//堆數據結構體
typedef struct
{
int key;
}element;
//堆最多存儲元素容量
element heap[MAX_ELEMENTS];
using namespace std;
//調整堆
void adjustHeap(element *a,int m,int size)
{
element temp=a[m];
int i=m,j;
j=m*2;//其左結點索引
while(j<=size)
{
//選取較大的那個子結點
if(j+1<=size&&a[j].key<a[j+1].key)
j++;
if(temp.key>=a[j].key) break;//滿足堆條件則跳出
else
{
a[i]=a[j];//作爲父節點
i=j;//調整交換過的子結點
j=2*i;//要被調整的子結點的左兒子
}
}
a[i]=temp;
}
void createMaxHeap(element *a,int size)
{
//從二叉樹中最後一個非葉子結點開始調整
for(int i=size/2;i>=1;i--)
adjustHeap(a,i,size);
}
最大堆或最小堆的插入操作就是先在堆樹的尾端插入一個結點,然後跟父結點比較,如果滿足堆條件或遇到根結點則結束,否則交換後繼續比較,然後再重複前面的操作,時間複雜度爲O(
就拿最大堆的插入操作爲例,調整過程如圖:
代碼實現:
void insert_max_head(element item,int size)
{
if(HEAP_FULL(size))
{
fprintf(stderr,"The heap is full \n");
exit(1);
}
int i=++size;//獲得最後一個結點索引
//比較新插入節點的值和父結點的值
//直到遇到根結點或滿足堆條件
while(i!=1&&item.key>heap[i/2].key)
{
heap[i]=heap[i/2];
i/=2;
}
heap[i]=item;
}
最大堆或最小堆的刪除操作就是刪除最頂端元素,然後用堆樹的最後一個結點補上,再做堆調整,其堆調整與建立堆一樣,故這裏不再重複描述,時間複雜度也爲O(
也拿最大堆爲例,刪除操作如圖:
代碼實現:
element delete_max_head(int size)
{
if(HEAP_EMPTY(size))
{
fprintf(stderr,"The heap is empty \n");
exit(1);
}
element item=heap[1];//刪除堆最頂端元素
heap[1]=heap[size];//將最後一個結點補爲頂端元素
size--;
adjustHeap(heap,1,size);//調整堆使其滿足堆條件
return item;
}