堆排序
堆是一种数据结构,一种叫做完全二叉树的数据结构。
堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。
大顶堆:a[i] >=a[2i+1] && ar[i] >= a[2i+2]
小顶堆:a[i] <= a[2i+1] && a[i] <= a[2i+2]
堆排序的基本思想:
堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
算法思想:
1.把一组数据a[n]调整成大根堆或小根堆,用heapSize来实时记录数组尚未排序的数据的数量,初始值为a[n]长度n
2.将a[0]与a[–heapSize]交换值,因为一开始就把数据调整为大根堆,该步骤相当于把已经找出数组中最大的数据,并放到了最后一位,不再处理。
3.a[0]与a[–heapSize]交换值后,也破坏了大根堆,但除了a[0]以外,数组其他数据还是保持大根堆状态。此时就是一直将a[0]数据“下沉”,让他不断和孩子节点比较,直到找到孩子节点都比它小,停止“下沉”,被破坏了的大根堆又重新被调整为大根堆。不断–heapSize,不断调整大根堆,每次都把a[0]与a[–heapSize]交换值,最终数组有序。
#include<bits/stdc++.h>
using namespace std;
void swap(int *a,int n,int m)
{
int t;
t=a[n];
a[n]=a[m];
a[m]=t;
}
void heapify(int *a,int index,int heapsize)
{
int left=index*2+1;
while(left<heapsize)//判断左孩子是否越界,若越界说明左孩子已经到达最下面
{
//比较两个孩子谁的值大 ,谁的值大谁就是largest
int largest=left+1<heapsize&&a[left+1]>a[left]?left+1:left;
//比较父节点和孩子节点的大小
largest=a[largest]>a[index]?largest:index;
if(largest==index)//若发现孩子节点都比a[index]小,则循环结束
break;
swap(a,largest,index);
index=largest;
left=index*2+1;
}
}
void heapInsert(int *a,int index)//把数组调成大根堆
{
while(a[index]>a[(index-1)/2])
{
swap(a,index,(index-1)/2);
index=(index-1)/2;
}
}
void heapSort(int *a,int n)
{
if(a==NULL||n<2)
return ;
for(int i=0;i<n;i++)
heapInsert(a,i);
int heapSize=n;
swap(a,0,--heapSize);//交换后大根堆的最大的值到数组最后一个位置
while(heapSize>0)
{
//每次都把数组中0-heapSize调整成大根堆
heapify(a,0,heapSize);
swap(a,0,--heapSize);
}
}
int main()
{
int n;
cin>>n;
int a[n];
for(int i=0;i<n;i++)
{
cin>>a[i];
}
heapSort(a,n);
for(int i=0;i<n;i++)
cout<<a[i]<<" ";
cout<<endl;
return 0;
}