这一篇主要讲解堆的定义,堆排序的实现。
我们熟知的堆,应该是内存中的“堆”,堆和栈是我们熟知的内存结构之一,通常,在一个函数中所运行的变量都是储存在栈帧中,可以说栈是系统自己开辟出来的。
而堆则是需要我们自己来进行分配(每个语言的分配语法都不尽相同,但都大同小异,我就不过多阐述了)。
但是这一篇,我们不讲这个“堆”,而是数据结构上的堆。
堆,又称是二叉堆,在数据结构上其实就是一种数组对象,因此二叉堆可以完全被视为一棵二叉树。而根据二叉树的定义,其父子结点,左右孩子结点的表示(c语言为例):
int PARENT(int i) return i/2;
int LEFT(int i) return 2*i;
int RIGHT(int i) return 2*i+1;
由此定义可以访问任意结点。
最大堆:最大堆是指某个结点的值至多适合其父结点的值一样大。(最小堆的定义相类似)
利用最大堆的性质,我们可以对任意堆进行堆进行下降操作:
void MAX_HEAPIFY(int a[],int i,int n)
{
int l,r,largest,temp;
l=LEFT(i);
r=RIGHT(i);
if(l<=n&&a[l]>a[i]) largest=l; //和左子节点进行比较
else largest=i;
if(r<=n&&a[r]>a[largest]) largest=r; //和右子节点进行比较
if(largest!=i)
{
temp=a[i];
a[i]=a[largest];
a[largest]=temp;
MAX_HEAPIFY(a,largest,n); //如果进行了交换,递归和子节点再进行比较
}
return;
{
int l,r,largest,temp;
l=LEFT(i);
r=RIGHT(i);
if(l<=n&&a[l]>a[i]) largest=l; //和左子节点进行比较
else largest=i;
if(r<=n&&a[r]>a[largest]) largest=r; //和右子节点进行比较
if(largest!=i)
{
temp=a[i];
a[i]=a[largest];
a[largest]=temp;
MAX_HEAPIFY(a,largest,n); //如果进行了交换,递归和子节点再进行比较
}
return;
}
由此函数使一般的堆转变为最大堆。
利用最大堆,我们可以对堆进行排序。排序的方法:利用最大堆的第一个结点(根结点)是所有结点中最大的性质,将第一个元素与最后一个元素交换,并将原来的n个元素缩减为n-1个元素,再进行“下降”操作,循环到只剩最后一项,完成排序。、
注意事项:进行循环的条件必须从最小的父结点开始(根结点是最大的根结点),想想为什么不能先从根结点开始。
void BUILD(int a[])
{
int i;
for(i=MAX_SIZE/2;i>0;i--) MAX_HEAPIFY(a,i,MAX_SIZE);
return;
}
{
int i;
for(i=MAX_SIZE/2;i>0;i--) MAX_HEAPIFY(a,i,MAX_SIZE);
return;
}