首先来引入一个例子:如何使用选择排序?
肯定是每一次遍历然后把大的放到最后面。(当然,前面也可以)
我感觉堆排序其实和选择差不多。
堆排序也是每次取出最大值,然后把最大值放后面
但是想学会堆排序,首先要知道什么是堆
#堆的定义
逻辑上:一个完全二叉树
物理上:借助向量实现
为什么能用一个向量来间接的弄一个完全二叉树呢?
(你自己试试把这个完全二叉树按层次遍历,是不是就是这个向量了)
如图,因为完全二叉树中间没有空缺,都是连续的,所以可以把完全二叉树存到数组中,这样就形为数组,神为完全二叉树。
#堆序性
就是说所有父亲的值大于孩子的值(等等你就知道为啥了,先记着:-D)
介绍一下下滤算法:
应该如何删除最上面的父亲?
对二叉树熟悉的你一定知道,如果要删除上面的,是先把最上面的和它右子树的最左边的那个叶子换位置,然后删除。
但是这样是不行的,首先:这个不是一个那样的树,不是都是顺序的。其次:这样做会破坏向量的有序性,导致后面都出错
应该把最后面的和最上面的交换,然后把新来的最上面的通过下滤操作重新变为堆就行了。
(j是你要让第几个下滤,n是总数(包括0))
void percolatedown(int *a,int j,int n)
{
if(n == 0)
return;
while(j <= (n - 1) / 2)
{
if((j + 1) * 2 > n)
{
if(a[j] < a[j * 2 + 1])
{
int t = a[j];
a[j] = a[j * 2 + 1];
a[j * 2 + 1] = t;
}
return;
}
int maxs = max(a,j * 2 + 1);
if(a[maxs] > a[j])
{
int t = a[j];
a[j] = a[maxs];
a[maxs] = t;
j = maxs;
}
else
{
return;
}
}
}
(因为神为二叉树,所以时间为O(logn))
如何让父亲的值大于孩子的值呢?
利用下滤操作,自上到下的都有序就行了
(代码中的i是总数,算0的,这样写方便)
void heapify(int *a,int i)
{
int j = 0;
for(j = (i - 1) / 2;j >= 0;j--)
{
percolatedown(a,j,i);
}
}
那么最重要的来了,如何进行堆排序呢?
每次把最大的值假装删除(实际是把最大的值移动到最后面),然后让总数-1就行了。
void sorts(int *a,int i)
{
int j = i;
int t = 0;
while(j > 0)
{
int m = a[0];
a[0] = a[j];
a[j] = m;
j--;
percolatedown(a,0,j);
}
}