堆的建立 - 小根堆
堆的建立有两种方法:一是直接在原有数组上从最后一个非叶子结点开始不段执行向下筛选算法。二是给定一个空堆,把数组中的元素一个一个插入到堆里,每插入一个元素都进行向上筛选。
法一的时间复杂度 O ( N ),法二的时间复杂度 O ( N logN )。
小根堆的向下筛选算法
//小根堆的向下筛选算法
void SiftDown(int* arr,int start,int m){
int i = start;
int j = 2*i + 1; //左孩子
int temp = arr[i];
while(j <= m){
if(j < m && arr[j] > arr[j+1]) j++; //选两孩子的小者
if(temp <= arr[j]) break; //根比小孩子小
else{ //双亲大向下滑动
arr[i] = arr[j];
i = j; //小孩子的位置给根
j = 2*j + 1; //继续向下筛选
}
arr[i] = temp; //找到自己目前合适的位置
}
}
时间复杂度 O ( logN )。
堆的建立 - 方法一
//建初堆
void CreateHeap(int* arr,int len){
for(int i = len/2 - 1;i >= 0;i --)
SiftDown(arr,i,len-1);
}
时间复杂度 O ( N )。
堆的插入 - 小根堆
小根堆的向上筛选算法
void SiftUp(int* arr,int start){ //从start开始,向上直到0,调整堆
int j = start;
int i = (j - 1)/2; //i是j的双亲
int temp = arr[j];
while(j > 0){
if(arr[i] <= temp) break;
else{
//双亲大向下落,继续向上检测
arr[j] = arr[i];
j = i;
i = (i - 1)/2;
}
}
arr[j] = temp;
}
时间复杂度 O ( logN )。
小根堆的插入
bool Insert(int* arr,int& len,int x){//堆、堆大小、插入元素
if(len == HeapSize) return false; //堆满
arr[len] = x; //插在堆尾
SiftUp(arr,len); //向上调整
len ++;
return true;
}
时间复杂度 O ( logN )。
堆的建立 - 方法二
void CreateHeap_2(int* arr,int* heap,int len){//数组、堆、数组长度
int k = 0;
for(int i = 0;i < len;i ++)
Insert(heap,k,arr[i]); //一次插一个
}
时间复杂度 O ( N logN )。
堆的删除 - 小根堆
bool Remove(int* arr,int& len,int& x){//堆,堆大小,保存要删除的元素
if(len == 0) return false;
x = arr[0];
arr[0] = arr[len - 1]; //把最后一个元素放到根
len --; //大小-1
SiftDown(arr,0,len-1); //调整
return true;
}
时间复杂度 O ( logN )。
完整代码:
#include<iostream>
using namespace std;
#define HeapSize 10
//小根堆的向下筛选算法
void SiftDown(int* arr,int start,int m){
int i = start;
int j = 2*i + 1; //左孩子
int temp = arr[i];
while(j <= m){
if(j < m && arr[j] > arr[j+1]) j++; //选两孩子的小者
if(temp <= arr[j]) break; //根比小孩子小
else{ //双亲大向下滑动
arr[i] = arr[j];
i = j; //小孩子的位置给根
j = 2*j + 1; //继续向下筛选
}
arr[i] = temp; //找到自己目前合适的位置
}
}
//建初堆
void CreateHeap_1(int* arr,int len){
for(int i = len/2 - 1;i >= 0;i --)
SiftDown(arr,i,len-1);
}
void SiftUp(int* arr,int start){ //从start开始,向上直到0,调整堆
int j = start;
int i = (j - 1)/2; //i是j的双亲
int temp = arr[j];
while(j > 0){
if(arr[i] <= temp) break;
else{
//双亲大向下落,继续向上检测
arr[j] = arr[i];
j = i;
i = (i - 1)/2;
}
}
arr[j] = temp;
}
bool Insert(int* arr,int& len,int x){
if(len == HeapSize) return false; //堆满
arr[len] = x; //插在堆尾
SiftUp(arr,len); //向上调整
len ++;
return true;
}
void CreateHeap_2(int* arr,int* heap,int len){
int k = 0;
for(int i = 0;i < len;i ++)
Insert(heap,k,arr[i]);
}
bool Remove(int* arr,int& len,int& x){
if(len == 0) return false;
x = arr[0];
arr[0] = arr[len - 1];
len --;
SiftDown(arr,0,len-1); //调整
return true;
}
int main(){
cout<<"法一建堆:"<<endl;
int arr[] = {2,3,1,7,5,9,0,8,6,4};
int len =10;
for(int i = 0;i < len;i ++) cout<<arr[i]<<" ";
cout<<endl;
CreateHeap_1(arr,10);
for(int i = 0;i < len;i ++) cout<<arr[i]<<" ";
cout<<endl;
cout<<"Remove:"<<endl;
int x;
cout<<Remove(arr,len,x)<<endl;
for(int i = 0;i < len;i ++) cout<<arr[i]<<" ";
cout<<endl;
cout<<"Insert:"<<endl;
cout<<Insert(arr,len,x)<<endl;
for(int i = 0;i < len;i ++) cout<<arr[i]<<" ";
cout<<endl;
cout<<"法二建堆:"<<endl;
int heap[HeapSize];
int arr_2[] = {2,3,1,7,5,9,0,8,6,4};
for(int i = 0;i < len;i ++) cout<<arr_2[i]<<" ";
CreateHeap_2(arr_2,heap,len);
cout<<endl;
for(int i = 0;i < len;i ++) cout<<heap[i]<<" ";
}
运行结果: