最简单,最直接的讲述堆排序
一、什么是堆,何来堆排序呢?
堆是一颗完全二叉树,且父节点必须大于子节点。什么叫完全二叉树呢,完全二叉树指的是前面n个节点都是满二叉树中的节点换句话说就是完全二叉树的子节点必须处于树的最后两行,且是从左到右的顺序。
二、堆排序的基本思想
通过对堆的调整得到根节点,因为调整后的根节点是整棵树最大的,这样就得到了此时的最大值,这时将这个根节点下标识数组第一个数,所以将其与最后一个数交换位置,这样,得到了第一个最大值,以此类推,可以得到一列数的顺序。这样得到的是最大推,当然也存在最小堆了,道理是一样的,只是父节点都小于子节点罢了。很多书上写的都是最大堆,我来写最小堆吧。
1、 在这里我们可以看到以数组为10 的例子来讲,首先这是一颗完全二叉树,但还不是堆,此时我们需要满足对的条件,那么我们需要子节点小于父节点那么这样才是一个堆。
2、我们通过对这个原理扫描一趟可以看到所有的父节点大于子节点,这样会出现一个问题,是什么问题呢,我们会惊人的发现在根节点的数大于任何一个节点的数这样我们就得到了这个数组中的最大值。按此结论我们可以通过10次循环可以不断的得到倒数第二大的数,倒数第三大的数以此类推,可以得到这个数组的顺序。
3、这里我们先需要解决一个问题,构建堆,第一次扫描我们知道了最大值,我们对剩余的数再建堆就可以得到第二大的数,我们可以放与数组的最后一这位交换位置,直到所有数都排序完毕。这个堆必须从底层向上扫描,因为我们知道做节点left = 2*i+1,右节点right = 2*I+2这样的话,必须从数组的最后向前扫描。我们通过递归调用我们的建堆就可以得到所有的父节点大于子节点直到根节点为当前的最大数。
4、这里最关见的一个问题是:我们必须在一个父节点,两个子节点中得出最大的值并交换位置,这样我们做递归调用就可以实现对整棵树的扫描。
关键步骤:
第一步是要得到一个子节点与父节点中的最小的然后交换得到父节点为此节点中最小的。
代码:
//创建堆的交换操作实现调整
/**
*@param int a[]表示数组
*@param int pos 表示比较的位置,可理解为父节点的下标
*@param int max 表示数组长度
*@return 无
*/
int heapAdjust(int a[],int pos,int maxLength){
int left = 2*pos+1;//左节点的下标
int right = 2*pos+2;//右节点的下标
int p = pos ;//表示指向最小值的“指针”用来记录最小值的下标
if(pos <maxLength&&pos>=0){
if(left<maxLength&&a[p]>=a[left]){
p = left;
}
if(right<maxLength&&a[p]>=a[right]){
p = right;
}
if(p != pos ){
int temp= 0;
temp = a[p];
a[p] = a[pos];
a[pos] = temp;
heapAdjust(a,p,maxLength);
}
}else{
cout<<"参数pos不合法!"<<endl;
return 0;
}
return a[0];
}
第二步是要重复调用得到根节点为此一列数中最小的值
代码:
//获取每一次排列时最小的数
/**
*@param int a[] 用来接收要排序的数组
*@param int maxLength 表示数组的长度
*@return int
*/
int GetHeap(int a[],int maxLength){
for(int i = maxLength-1;i>=0;i--){
heapAdjust(a,i,maxLength);
}
cout<<"---------------------------每一次找到的最小值:---------------------------"<<a[0]<<endl;
return a[0];
}
第三步是堆的排序,将得到的根节点中的最小值放入对应的数组中。
代码:
//用来排序的将每一次得到的最小值进行排序
/**
*@param int a[] 用来接收要排序的数组
*@param int maxLength 表示数组的长度
*@return int
*/
void heap_Sort(int a[],int maxLength){
int temp = 0;
int count = 0;
for(int i = maxLength-1;i>=0;i--){
GetHeap(a,i+1);//此处i+1是为了保持数组的长度不变
temp = a[0];
a[0]=a[i];
a[i] =temp;
count++;
cout<<"count="<<count<<endl;
}
}
最后是输出:
这里强调的是:子节点:left = 2i +1,right = 2i+2 父节点:i
全部实现代码:
/**
*堆排序的实现
*@author 菜鸟
*@version 2014.6.12
*/
#include <iostream>
#include <windows.h>
using namespace std;
//创建堆的交换操作实现调整
/**
*@param int a[]表示数组
*@param int pos 表示比较的位置,可理解为父节点的下标
*@param int max 表示数组长度
*@return 无
*/
int heapAdjust(int a[],int pos,int maxLength){
int left = 2*pos+1;//左节点的下标
int right = 2*pos+2;//右节点的下标
int p = pos ;//表示指向最小值的“指针”用来记录最小值的下标
if(pos <maxLength&&pos>=0){
if(left<maxLength&&a[p]>=a[left]){
p = left;
}
if(right<maxLength&&a[p]>=a[right]){
p = right;
}
if(p != pos ){
int temp= 0;
temp = a[p];
a[p] = a[pos];
a[pos] = temp;
heapAdjust(a,p,maxLength);
}
}else{
cout<<"参数pos不合法!"<<endl;
return 0;
}
return a[0];
}
//获取每一次排列时最小的数
/**
*@param int a[] 用来接收要排序的数组
*@param int maxLength 表示数组的长度
*@return int
*/
int GetHeap(int a[],int maxLength){
for(int i = maxLength-1;i>=0;i--){
heapAdjust(a,i,maxLength);
}
cout<<"---------------------------每一次找到的最小值:---------------------------"<<a[0]<<endl;
return a[0];
}
//用来排序的将每一次得到的最小值进行排序
/**
*@param int a[] 用来接收要排序的数组
*@param int maxLength 表示数组的长度
*@return int
*/
void heap_Sort(int a[],int maxLength){
int temp = 0;
int count = 0;
for(int i = maxLength-1;i>=0;i--){
GetHeap(a,i+1);//此处i+1是为了保持数组的长度不变
temp = a[0];
a[0]=a[i];
a[i] =temp;
count++;
cout<<"count="<<count<<endl;
}
}
//写一个输出函数
/**
*@parame int a[] 用来接收需要输出的数组长度
*@param int maxLength 表示数组的长度
*@return 无
*/
void out_put(int a[],int maxLength){
for(int i = 0;i < maxLength;i++){
cout <<"第"<<(i+1)<<"个元素:"<<a[i]<<endl;
}
}
int main(){
int a[11] = {11,9,1,4,2,3,5,7,6,8,0};
cout<<"未排序之前数组元素:"<<endl;
out_put(a,11);
heap_Sort(a,11);
cout<<"排序之后的数组元素:"<<endl;
for(int i = 10;i >=0;i--){
cout <<"第"<<(i+1)<<"个元素:"<<a[i]<<endl;
}
system("PAUSE");
return 0;
}
以上代码经验证过!