基本概念:
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);
}
}