前言
本文中的代码实现的是最小堆,最大堆的原理与此相似,故省略;另外,由于二叉堆插入结点与删除结点的操作相反,所以本文中也只实现插入结点的操作,删除结点的操作的实现略去。
阅读文中代码所需的预备知识
- 二叉堆是一个完全二叉树,但是它的存储方式并不是链式存储,而是顺序存储,即二叉树的所有结点都存储在数组中。
- 若父结点在数组中的下标是parent,则其左孩子的下标是2*parent+1,右孩子的下标是2*parent+2。
- 二叉堆插入结点时,插入位置是完全二叉树的最后一个位置。
- 构建二叉堆,就是把一个无序的完全二叉树调整为二叉堆,本质就是让所有非叶子结点从最后一个非叶子结点开始依次“下沉”。最后一个非叶子结点的数组下标的计算方法是:(数组长度-2)/ 2。
代码
#include<iostream>
using namespace std;
//分别用于存储array1和array2的长度
int len1,len2;
//结点的“上浮”过程
void upAdjust(int *array){
int childIndex=len1-1;
//求出父结点的下标
int parentIndex=(childIndex-1)/2;
//temp保存插入的叶子结点的值,用于最后的赋值
int temp=array[childIndex];
while(childIndex>0&&temp<array[parentIndex]){
//无需真正交换,单向赋值即可
array[childIndex]=array[parentIndex];
childIndex=parentIndex;
parentIndex=(childIndex-1)/2;
}
array[childIndex]=temp;
}
//结点的“下沉”过程
void downAdjust(int *array,int parentIndex,int len){
//temp保存父结点值,用于最后的赋值
int temp=array[parentIndex];
//求出左孩子的下标
int childIndex=2*parentIndex+1;
while(childIndex<len){
//如果有右孩子,且右孩子小于左孩子的值,则定位到右孩子
if(childIndex+1<len&&array[childIndex+1]<array[childIndex]){
childIndex++;
}
//如果父结点的值小于任何一个孩子结点的值,则直接跳出
if(temp<=array[childIndex])
break;
//无需真正交换,单向赋值即可
array[parentIndex]=array[childIndex];
parentIndex=childIndex;
childIndex=2*childIndex+1;
}
array[parentIndex]=temp;
}
//二叉堆的建立
void buildHeap(int *array){
//从最后一个非叶子结点开始,依次做"下沉"调整
for(int i=(len2-2)/2;i>=0;i--){
downAdjust(array,i,len2);
}
}
int main()
{
//array1用于测试在一个二叉堆插入一个数后,堆的"上浮"调整
int array1[]={1,3,2,6,5,7,8,9,10,0};
len1=sizeof(array1)/sizeof(array1[0]);
upAdjust(array1);
cout<<"调整后的堆是: ";
for(int i=0;i<len1;i++)
cout<<array1[i]<<" ";
cout<<endl;
//array2用于测试由一个数组建立二叉堆时,堆的"下沉"调整
int array2[]={7,1,3,10,5,2,8,9,6};
len2=sizeof(array2)/sizeof(array2[0]);
buildHeap(array2);
cout<<"建成的堆是: ";
for(int i=0;i<len2;i++)
cout<<array2[i]<<" ";
cout<<endl;
return 0;
}