收获
1:学习了如何建堆,以及如何使用堆进行排序,一般使用堆排序都是先建立一个初始堆,然后再一点一点遍历排序,如果想要升序则建立大根堆,想要降序排序,建立小根堆
2:比较重点需要掌握的知识:建堆的时候如果数组的下标是从0开始,则第一个要调整的元素为length/2-1,同时每一个节点的左孩子是2i+1,右孩子是2i+2这点需要注意一下!(因为有的时候会采取以节点数目为判断进行建堆等处理,下标是从1开始~)
代码(大根堆)
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
void HeapAdjust(int *a,int i,int Size)//这里i表示数组下标
{
int r=2*i+2,l=2*i+1;//此时还是以序号标记
int Max=i,mid;
if(i<=Size/2-1){//确定当前i是否根结点
//确定当前是否有右子结点,符合条件为有
if(r<Size){
//有右结点的话判断谁大
if(a[l]<a[r]) mid=r;
else mid=l;
// 将大的那个跟根结点比,如果子结点大则改变Max的指向
if(a[mid]>a[i]) Max=mid;
}
//否则没有,没有的话判断是否有左子结点,有的话就与根结点对比
else if(l<Size && a[l]>a[i]) Max=l;
//如果最大的节点不是根结点,则:
if(Max!=i){
swap(a[Max],a[i]);
HeapAdjust(a,Max,Size);//这里主要是确定交换之后的子结点值依旧满足大根堆性质即大于子结点的子节点的值,可以将这条语句用递归理解,本质上是将较小的值沉到下面;
}
}
}
void BuildHeap(int *a,int Size)//建造二叉树堆
{
int i;
for(i=Size/2-1;i>=0;i--)//最大的有叶子结点是size/2-1;手画完全二叉树图即可以证明
{
HeapAdjust(a,i,Size);
}
}
//唔~舒服了一丢丢,果然还是理解了原理最棒的!
int main()
{
int a[]={40,55, 49, 73, 12, 27, 98, 81, 64, 36};
int Size=sizeof(a)/sizeof(a[0]);
BuildHeap(a,Size);
cout<<"第一次建堆结果"<<endl;
for(int i=0;i<Size;i++)//展示第一次建堆的结果
cout<<a[i]<<' ';
cout<<'\n';
for(int i=Size;i>=1;i--){//逐个进行堆排序
swap(a[0],a[i-1]);
HeapAdjust(a,1,i-1);
}
cout<<"最终排序结果"<<endl;
for(int i=0;i<Size;i++)//展示最终排序结果
cout<<a[i]<<' ';
cout<<'\n';
return (0);
}
代码(小根堆)
大根堆和小根堆的建立过程,区别就是在于调整堆的时候谁在上面,谁在下面~
//小根堆调整
void HeapAdjust(int *a,int i,int Size){
int r=i*2+2,l=i*2+1;
int Min=i,mid;
if(i<=Size/2-1){
if(r<Size){
if(a[l]>a[r])mid=r;
else mid=l;
if(a[mid]<a[i]) Min=mid;
}else if(l<Size&&a[l]<a[i]) Min=l;
if(Min!=i){
swap(a[Min],a[i]);
HeapAdjust(a,Min,Size);
}
}
}
参考链接
https://www.cnblogs.com/deng-dw/p/15220236.html
大顶堆、小顶堆及其建堆过程、堆排序