前言
从之前的堆的学习中我们知道了堆这种数据结构的表现形式为什么样的,通过堆的特性,小堆的最开始的节点一定是最小的,大堆最开始的节点一定是最大的特性,我们可以使用堆来实现排序。
堆排序的实现
1.如何实现排序
我们通过堆的特性我们可以明白当堆创建成功后,堆顶的数据小堆就为最小,大堆就为最大,我们可以将堆顶的数和堆最后的数进行交换,此时再将剩下的数据继续创建堆,交换后最后只剩一个数就实现了排序。
2.创建大小堆
我们需要运用两种方式向上调整和向下调整来完成堆的创建,向上调整是通过子节点和父节点的比较来看是否需要交换来表示的,所以向上调整的函数我们传递子节点。
void Adjustup(int* a, int child)
{
int parent = (child -1) / 2;
while (child > 0)
{
if (a[child] > a[parent])
{
Swap(&a[child], &a[parent]);
child=parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
实现向下调整,我们是传递父节点,使父节点和子节点进行比较来看是否需要进行交换,一般因为向下调整是从最上面向下进行实现的,所以要保证除了最开始交换了数值堆的功能,其他的节点要满足堆的功能,要注意的是我们需要多传堆的大小,因为我们通过堆来算出它的两个子节点的时候有可能会出现越界的情况,通过堆的大小可以判断出是否算出了不存在的子节点。
void Adjustdown(int* a, int parent, int n)
{
int child = parent * 2 + 1;
while (child < n)
{
if (a[child] < a[child + 1] && (child + 1) < n)
{
child = child + 1;
}
if (a[child] > a[parent])
{
Swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
我们使用的排序是否为升序和降序来判断使用大堆还是小堆,我们根据大小堆的特性从而得出,
如果是升序排序就使用大堆,如果使用降序排序就使用小堆。
void hopesort(int* a, int n)
{
int i = 0;
for (i = 1; i < n; i++)
{
Adjustup(a, i);
}
//for (i = (n - 1 - 1) / 2; i >= 0; i--)
//{
// Adjustdown(a, i,n-1);
//}
int end = n - 1;
while (end > 0)
{
Swap(&a[end], &a[0]);
Adjustdown(a, 0, end);
end--;
}
}
首先使用向上排序或者向下排序使其变为大堆或者小堆,将最后的节点和最前的节点进行交换,最后使用向下调整使其继续变为大堆或者小堆然后进行交换。
总结
堆排序是一种效率很高的一种算法,在使用的时候要熟悉堆的特性,通过使用向上调整和向下调整再次使其变为堆,重复实现最后完成排序。