堆的概念及堆排序思路:
二叉堆是完全二叉树,或者近似完全二叉树。
二叉堆满足两个特性:
---1、父节点的键值总是大于或等于(小于或等于)任何一个节点的键值;
---2、每个节点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
任何节点的值都大于其子节点的值------大顶堆
任何节点的值都小于其子节点的值------小顶堆
堆排序:
1、堆化,反向调整使得每个子树都是大顶或者小顶堆;
2、按序输出元素:把堆顶和堆末元素对调,然后调整堆顶元素。
伪代码:
MakeMinHeap(A){
n=A.length;
for i from n/2-1 down to 0{
MinHeapFixDown(A,i);
}
}
/*
①、先看有没有左右孩子;
②、找到左右孩子中较小的那个;
③、调整(交换或者不交换);
④、递归地向下调整。
*/
MinHeapFixDown(A,i,n){
//找到左右孩子
left=2*i+1;
right=2*i+2;
//左孩子已经越界,i就是叶子节点
if(left>=n){
return;
}
min=left;
if(right>=n){
min=left;
}
else{
if(A[right]<A[left]){
min=right;
}
}
//min指向了左右孩子中较小的那个
//如果A[i] 比两个孩子都要小,不用调整
if(A[i]<=A[min]){
return;
}
//否则,找到两个孩子中较小的,和i交换
temp=A[i];
A[i]=A[min];
A[min]=temp;
//小孩子那个位置的值发生了变化,i变更为小孩子那个位置,递调整
MinHeapFixDown(A,min,n);
}
//sort函数:
sort(A){
//先对A进行堆化
MakeMinHeap(A);
for(int x=n-1;x>=0;x--)
//把堆顶,0号元素和最后一个元素对调
swap(A,0,x);
//缩小堆的范围,对堆顶元素进行向下调整
MinHeapFixDown(A,0,x-1);
}
代码:
#include<iostream>
using namespace std;
/**
*思路:首先要知道大顶堆和小顶堆,数组就是一个堆,每个i节点的左右孩子是2i+1和2i+2
* 有了堆,将其堆化:从n/2-1个元素开始向下修复,将每个节点修复为小(大)顶堆
* 修复完成后,数组具有小(大)顶堆的性质
* 按序输出:小顶堆可以对数组逆序排列,每次交换堆顶和末尾元素,对栈顶进行向下修复
*
*时间复杂度:堆化:一半的元素修复,修复是单分支的,所以整体堆化为nlgn。(PS:常数因子较大)
*排序:n个元素都要取出,因此调整为n次,每次调整修复同上是lgn的,整体为nlgn
*空间复杂度:不需要开辟辅助空间
*原址排序
* 稳定性:不稳定
*/
void MinHeapFixDown(int A[],int i,int n);
void makeMinHeap(int A[],int length){
int n=length;
for(int i=n/2-1;i>=0;i--){
MinHeapFixDown(A,i,n);
}
}
//向下调整函数
void MinHeapFixDown(int A[],int i,int n){
//找到左右孩子
int left=2*i+1;
int right=2*i+2;
//左孩子已经越界,i就是叶子节点
if(left>=n){
return;
}
int min=left;
if(right>=n){
min=left;
}
else{
if(A[right]<A[left]){
min=right;
}
}
//min指向了左右孩子中较小的那个
//如果A[i]比两个孩子都要小,不用调整
if(A[i]<A[min]){
return;
}
//否则,找到两个孩子中较小的,和i交换
int temp=A[i];
A[i]=A[min];
A[min]=temp;
//小孩子那个位置的值发生了变化,i变更为小孩子的那个位置,递归调整
MinHeapFixDown(A,min,n);
}
//排序函数
void sort(int A[],int length){
//先对A进行堆化
makeMinHeap(A,length);
for(int x=length-1;x>=0;x--){
//把堆顶,0号元素和最后一个元素对调
swap(A[0],A[x]);
//缩小堆的范围,对堆顶元素进行向下调整
MinHeapFixDown(A,0,x);
}
}
int main(){
int arr[]={6,2,5,8,2,1,9,5,6};
int len= 9;
sort(arr,len);
for(int i=0;i<len;i++){
cout<<arr[i]<<" ";
}
return 0;
}