堆排序是经典的排序问题中,非常重要的一种排序算法,实际上堆排序并没有特别之处,其主要的特点是将数组抽象成一个堆的结构。然后通过堆的二叉树性质进行排序。也正是由于利用了二叉树的性质,所以堆排序的时间复杂度能够达到O(nlogn)。
下面的总结和比较,主要针对两种堆排序实现进行一个比较。突出两种实现方式对堆排序算法的细微区别和作者对算法的理解,实际上其本质是一样的。第一种是笔者参考机械工业出版社《数据结构》一书中,提出来的算法进行写的代码。两种实现方式中,算法效率更高效的是后者。
#include <iostream>
#include <iomanip>
#include <cstdlib>
using namespace std;
void adjust(int array[],int root,int n) //这个调整的函数,效率有一些低,因为它每次都是从最后一个父节点,开始调整堆,实际上其实是不需要每一次都从最后一个父节点开始调整堆的,因为秩序对改变堆的地方进行重新调整堆的操作
{
int child;
int rootkey = array[root];
child = 2 * root;
while(child<=n-1) //这个循环就是直接从堆排序中的二叉树的最后一个父节点,开始调整堆。
{
if((child<n)&&(array[child]<array[child + 1]))//寻找左右子节点中,权值更大的那个子节点
child++;
if(rootkey>array[child])//如果父节点的权值大,跳到下一个循环
break;
else//如果子节点的权值,比父节点大,此时开始交换子节点和父节点的权值
{
array[child/2] = array[child];
child *= 2;
}
}
array[child/2] = rootkey;
}
void heapsort(int array[],int n)
{
int i,j;
int temp;
for(i=n/2;i>=0;i--)
adjust(array,i,n);
for(i=n-1;i>=0;i--)
{
temp = array[0];
array[0] = array[i+1];
array[i+1] = temp;
adjust(array,0,i);
}
}
int main()
{
const int NUM=20;
int arr[] = {1,10,11,5,6,15,0,15,16,14,0,8,17,15,7,19,17,1,18,7};
for(int i=0;i<20;i++)
{
cout<<arr[i]<<" ";
}
heapsort(arr,20);
cout<<endl;
for(int i=0;i<20;i++)
{
cout<<arr[i]<<" ";
}
system("PAUSE");
return 0;
}
第二种,是我从博客园上看到的一个博主写的帖子,我觉得很有意思,其对堆排序的理解其实是非常深刻的。下面就对他的方法做一个诠释和总结。这个实现的知识产权属于原作者:http://www.cnblogs.com/dolphin0520/archive/2011/10/06/2199741.html
#include<iostream>
#include<cstdlib>
using namespace std;
void HeapAdjust(int* array,int i,int size)//与上述堆排序实现不同的就体现在这个调整堆的理解上,作者的实现其实只对需要调整的结点进行了堆调整
{
void Swap(int &a,int &b);
int left = 2*i+1;
int right = 2*i+2;
int max = i;
if(i<=size/2)//如果堆排序中的最大堆和最小堆建好了以后,每一次调整堆,如果某一个父节点与其子节点做了调整,实际上接下来的只需要对子节点所在的每一个小的二叉树进行调整,这个步骤比上面的调整堆算法要高效一些
{
if((left<=size)&&(array[left]>array[max]))
{
max = left;
}
if((right<=size)&&(array[right]>array[max]))
{
max = right;
}
if(max != i)//如果当前进行了堆排序的调整,那么接下来做一个递归的调用,对子节点的小二叉树进行堆调整的操作,维持最大堆或者最小堆的性质
{
Swap(array[i],array[max]);
HeapAdjust(array,max,size);
}
}
}
void Swap(int &a,int &b)
{
int temp = a;
a = b;
b = temp;
}
void BuildHeap(int *array,int size)
{
for(int i = size/2;i>=0;i--)
HeapAdjust(array,i,size);
}
void HeapSort(int *array,int size)
{
void BuildHeap(int *array,int size);
BuildHeap(array,size);
for(int i=size;i>=0;i--)
{
Swap(array[0],array[i]);
HeapAdjust(array,0,i-1);
}
}
int main(int argc,char** argv)
{
int a[100];
int size;
cout<<"Please input the array:";
while(scanf("%d",&size)==1&&size>0)
{
int i;
for(i=0;i<=size-1;i++)
{
cout<<"Please input array["<<i<<"]:";
cin>>a[i];
}
HeapSort(a,size-1);
cout<<"After Heap Sort,the Array is:"<<endl;
for(i=0;i<=size-1;i++)
cout<<a[i]<<" ";
cout<<endl;
}
return 0;
}