基本概念:
1、完全二叉樹:若二叉樹的深度爲h,則除第h層外,其他層的結點全部達到最大值,且第h層的所有結點都集中在左子樹。
2、滿二叉樹:滿二叉樹是一種特殊的的完全二叉樹,所有層的結點都是最大值。
1、堆是一顆完全二叉樹;
2、堆中的某個結點的值總是大於等於(最大堆)或小於等於(最小堆)其孩子結點的值。
3、堆中每個結點的子樹都是堆樹。
假設原始數據爲a[]={4,1,3,2,16,9.10.14.8.7},採用順序存儲對應的完全二叉樹爲:
堆的數據結構如下
struct MaxHeap { EType *heap; //存放數據的空間,下標從1開始存儲數據,下標爲0的作爲工作空間,存儲臨時數據。 int MaxSize; //MaxSize是存放數據元素空間的大小 int HeapSize; //HeapSize是數據元素的個數 }; MaxHeap H;
1、構造最大堆
基本思想:首先將每個葉子結點視爲一個堆,再將每個葉子結點於其父節點一起構成一個包含更多結點的堆。所以在構造堆的時候,首先需要找到最後一個結點的父節點,從這個節點開始構造最大堆,直到該節點前面的所有分支節點都處理完畢。
注意: 在二叉樹中,若當前節點的下標爲 i, 則其父節點的下標爲 i/2,其左子節點的下標爲 i*2,其右子節點的下標爲i*2+1;
2、初始化堆
void MaxHeapInit(MaxHeap &H) { for(int i=H.HeapSize/2;i>=1;i--) { H.heap[0]=H.heap[i]; int son=i*2; while(son<H.HeapSize) { if(son<H.HeapSize&&H.heap[son]<H.heap[son+1]) son++; if(H.heap[i]>H.heap[son]) break; else if(son<H.heapSize&&H.heap[son]>H.heap[son+1] { H.heap[son/2]=H.heap[son]; son*=2; } } H.heap[son/2]=H.heap[0]; } }
下圖是原始數據堆初始化的過程
3、最大堆中插入節點
最大堆中插入節點,先在堆末尾插入該節點,然後按照堆的初始化過程將該節點放入到合適的位置。
void MaxHeapInsert(MaxHeap &H, EType &x) { if(H.HeapSize==H.MaxSize) return false; int i=++H.HeapSize; while(i!=1&&x>H.heap[i/2]) { H.heap[i]=H.heap[i/2]; i/=2; } H.heap[i]=x; return true; }
4\最大堆中刪除節點
將最大堆的最後一個節點放到根節點,然後刪除最大值,然後再把新的根節點放到合適的位置
void MaxHeapDelete(MaxHeap &H, EType &x) { if(H.HeapSize==0) return false; x=H.heap[1]; H.heap[0]=H.heap[H.HeapSize--]; int i=1, son=i*2; while(son<H.HeapSize) { if(son<H.HeapSize&&H.heap[son]<H.heap[son+1]) son++; if(H.heap[i]>H.heap[son]) break; H.heao[i]=H.heap[son]; i=son; son*=2; } H.heap[i]=H.heap[0]; return true; }
5、堆排序
#include<iostream> using namespace std; void swap(int &a, int &b) { int temp=a; a=b; b=temp; } void quick_build(int a[], int len, int root) { int left=root*2+1; int flag=left; while(left<len) { int right=left+1; while(right<len&&a[right]>a[left]) flag=right; } if(a[root]<a[flag]) { swap(a[root],a[flag]); heap_build(a,len,flag); } void quick_sort(int a[], int len) { for(int i=len/2;i>0;i--) heap_build(a,len, i); for(int j=len-1;j>0;j--) { swap(a[0],a[j]); heap_build(a,0,j); } }