堆排序
是一种在位的排序,也就是在任何时候,数组中只有常数个元素存储在数组外,在堆中分别分为大顶堆与小顶堆,也就是最大的元素在堆顶或者最小的元素在堆顶。
快速排序的实现往往要优于堆排序。它可以作为高效的优先级队列。
最大优先级队列的一个应用就是在分是计算机进行作业调度。要对作业间的优先关系加以记录。当作业被中断后,选择具有高级优先级的作业,最小优先级队列的应用:基于事件驱动的模拟器中,队列中各项是模拟的事件,每一个都有一个发生时间作为其关键字。
堆可以被视作为一个完全的二叉树。
两个属性:
1)每个结点的值不会小于它的子结点的值(但是在子结点中是无序的)
2)树是完全平衡的,最底层的叶子结点都位于最左边的位置上
缺点:
数据移动的幅度很大,将数组中最左边的元素移到右边花费的时间很多,因为移动后就要重新的调整堆。时间复杂度为O(n)+O(nlogn)+(n-1)=O(nlogm)
主要思想:
将最大的元素放在数组的末尾,重新调整堆的结构。接着将第二大的元素放在最大元素前面那个位置。于是没循环一次就会有一个元素在堆的末尾,堆中元素被移走一个。
template<class T>
void HeapTree<T>::MAX_HEAPIFY(T *heapArray,int index,int length)//执行时间为logn
{
T temp;
int changeIndex=0;
while(index*2<length-1)
{
changeIndex=index*2+1;
if (index*2+2<length)
{
if (*(heapArray+(index*2+1))<*(heapArray+(index*2+2)))
{
changeIndex=index*2+2;//与左子树进行比较
}
}
if (*(heapArray+index)<*(heapArray+changeIndex))//若是孩子结点比当前的结点的值更大
{
temp=*(heapArray+index);
*(heapArray+index)=*(heapArray+changeIndex);
*(heapArray+changeIndex)=temp;
index=changeIndex;//进行转换,也许下面会影响,继续的建堆
}
else
{
break;
}
}
}
template<class T>
void HeapTree<T>::BUILD_MAX_HEAP(T *heapArray,int length)//执行时间为O(n)
{
nodeNum=length;
for (int index=length/2;index>0;index--)
{
MAX_HEAPIFY(heapArray,index-1,length);//对每个元素进行判断,调整堆
}
}
template<class T>
void HeapTree<T>::HEAPSORT(T *heapArray,int length)//执行时间为nlog(n)
{
//主要思想:首先将数组中元素构建成一个大顶堆。在构建的过程从最后一个节点的父节点开始,分析比较到最大元素到相应的位置
//并将父节点替换到元素大的子结点的位置,这个时候可能子结点的子结点元素又会比这个更大,于是就有了函数中的循环判断
//排序的过程:将顶元素与最后一个元素进行替换,这个时候顶元素必定是最大的元素,于是,就会有从小到大的排序。
for (int index=length/2;index>0;index--)
{
MAX_HEAPIFY(heapArray,index-1,length);//对每个元素进行判断,调整堆
}
while(length>1)
{
T temp=*heapArray;
*heapArray=*(heapArray+length-1);
*(heapArray+length-1)=temp;
length--;
MAX_HEAPIFY(heapArray,0,length);//在堆中并不能保证左右子树的值的大小是按序的,于是采用,当前的与最后的交换
}
}
template<class T>//返回最大元素,并删除这个元素,就是返回顶端元素
T HeapTree<T>::HEAP_EXTRACT_MAX(T *heapArray,int length)
{
if(length<1)
{
cout<<"heap underflow";
}
T max=*heapArray;
*heapArray=*(heapArray+length-1);
*(heapArray+length-1)=max;
MAX_HEAPIFY(heapArray,0,length-1);
return max;
}