自己写了下二叉堆的一些操作以及堆排序
主函数就是下面这样,每个操作都是一个独立的函数,方便查看
然后我的是以最大堆为例的,最小堆操作几乎一样,就是大于小于号的修改
然后我喜欢下标从1开始,就把a[0]给废掉了,这样子可读性也强些
从0开始的也差不多,就是对于编号为K的结点,儿子结点编号分别为Kx2+1和Kx2+2(这里的"X"是乘号的意思,好像写博客的时候米字符和加粗操作有重合地方)
然后注意upAdjust和downAdjust里面那些结点数据的上浮和下沉其实是用了直接插入排序的思想,从那个temp记录初始的数据应该可以看出,这样比交换好一点
int main()
{
Create();//构建最大堆
Delete();//删除堆顶元素
Insert();//插入一个元素
Heap_Sort();//堆排序,升序
}
无序堆构造最大堆
void PRINT(int *a,int N)
{
for(int i=1;i<=N;i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
void downAdjust(int *a,int N,int i){
int fa_index,child_index,temp;
fa_index=i;
child_index=fa_index*2;
temp=a[fa_index];//先记录
while(child_index<=N)
{
if(child_index+1<=N)//如果有右孩子结点
{
if(a[child_index+1]>a[child_index])//
{
child_index++;
}
}//得到最大子结点的小标
if(temp>a[child_index]){
break;
}
a[fa_index]=a[child_index];
fa_index=child_index;
child_index=child_index*2;
}
a[fa_index]=temp;
}
void Create()
{
int N=10;
int a[N+1]={0,14,9,6,13,21,10,16,17,2,12};//构造用的无序数组
int i;
for(i=N/2;i;i--)//从编号最大的有子结点的结点开始到结点1
{
downAdjust(a,N,i);//对每个结点进行下沉
}
printf("构造出的最大堆为:\n");
PRINT(a,N);
}
最大堆的删除顶结点操作
//删除和构造都是用的下沉调试操作
void PRINT(int *a,int N)
{
for(int i=1;i<=N;i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
void downAdjust(int *a,int N,int i){
int fa_index,child_index,temp;
fa_index=i;
child_index=fa_index*2;
temp=a[fa_index];//先记录
while(child_index<=N)
{
if(child_index+1<=N)//如果有右孩子结点
{
if(a[child_index+1]>a[child_index])//
{
child_index++;
}
}//得到最大子结点的小标
if(temp>a[child_index]){
break;
}
a[fa_index]=a[child_index];
fa_index=child_index;
child_index=child_index*2;
}
a[fa_index]=temp;
}
void Delete()
{
int N=10;
int a[N+1]={0,21,17,16,14,12,10,6,13,2,9};//已建好的最大堆
a[1]=a[N--];//把结点1用最后一个结点替换掉,并且N要减1
downAdjust(a,N,1);//把结点1下沉
printf("删除后的最大堆为:\n");
PRINT(a,N);
}
最大堆的插入操作
void PRINT(int *a,int N)
{
for(int i=1;i<=N;i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
//插入是把要插入的数放在数组末尾,再向上调试
void upAdjust(int *a,int N)
{
int index=N;
int fa_index=N/2;
int temp=a[index];
while(fa_index)
{
if(temp<a[fa_index])
{
break;
}
a[index]=a[fa_index];
index=fa_index;
fa_index=index/2;
}
a[index]=temp;//这里也用了插入排序的思想
}
void Insert()
{
int N=10;
int a[N+2]={0,21,17,16,14,12,10,6,13,2,9};//已建好的最大堆
int tar=23;//可以修改
a[++N]=tar;//记得N要加一
upAdjust(a,N);
printf("插入%d后的最大堆为:\n",tar);
PRINT(a,N);
}
堆排序
void downAdjust(int *a,int N,int i){
int fa_index,child_index,temp;
fa_index=i;
child_index=fa_index*2;
temp=a[fa_index];
while(child_index<=N)
{
if(child_index+1<=N)
{
if(a[child_index+1]>a[child_index])
{
child_index++;
}
}//得到最大儿子结点的小标
if(temp>a[child_index]){
break;
}
a[fa_index]=a[child_index];
fa_index=child_index;
child_index=child_index*2;
}
a[fa_index]=temp;
}
void Heap_Sort()
{
int N=10,size=N;
int a[N+1]={0,21,17,16,14,12,10,6,13,2,9};//已建好的最大堆
//这里我偷懒了,直接用的最大堆,如果一开始堆是无序的,要先构建最大堆
int temp;
while(size)
{
int temp=a[size];
a[size]=a[1];
a[1]=temp;//这三行就是交换a[1]和a[N],这样可以让每次a[N]都是最大的
printf("%d ",a[size--]);//记得减一
downAdjust(a,size,1);//每次把那两个结点交换后再把堆变为最大堆,始终保持堆顶元素最大
}
}