概述
堆排序利用堆的性质来对数组进行排序,也就是说它的所有操作都是在数组上进行的,类似于树状数组的形式;并不是通过实际上的二叉树排序。
要实现堆排序,首先需要了解堆排序的原理。
堆排序原理:
- 堆的结构类似于完全二叉树,头节点位于整个结构的最上方,每个父节点从左到右依次分岔,延申出两个子节点。
- 每层节点从左到右在数据中是依次排列的关系。
-
堆中某个结点的值总是不大于其父结点的值(大顶堆:头节点值最大)。
-
堆中某个结点的值总是不小于其父结点的值(小顶堆:头节点值最小)。
因为是排序算法,所以这里不用二叉树结构实现堆结构,使用数组模拟并将其想象成一棵树:
arr = { 0, 1, 2, 3, 4, 5, 6 };
上图的每个位置分别对应一个数组的元素下标
HeapInsert:(末尾插入)
假设这个堆有序,且每个父节点的值大于等于其子节点(大顶堆):
假如上图是一个数组arr,想要在该数组末尾插入一个数字10,并且变更数组元素的顺序使得堆结构依然成立。
- 我们只需要遵守堆结构的基本顺序进行比较排序即可
因为 堆中某个结点的值总是不大于或不小于其父结点的值,所以需要将2位置(8)和6位置(10)进行比较,当子节点的数值大于父节点,则该子节点和父节点进行交换,即8 与 10 交换。
完成上个步骤,将需要操作的光标变成位置2(10),继续与其父节点位置0(9)进行比较,若大于其父节点,则交换,否则跳出循环。到这里一个插入操作结束。
代码如下:
void Swap(int *arr, int x, int y)
{
int temp = 0;
temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
void HeapInsert(int *arr, int index)
{
while (arr[index] > arr[(index - 1) / 2])
{
//交换函数swap
Swap(arr, index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
HeapIfy:(中间插入向下比较)
假设对刚才的数组首元素进行变更,那么要如何使该数组保持堆数组
若将首元素替换为7,则需要如何进行变动?
- 第一步:找出子节点中较大的数字。
- 第二步:父节点与子节点中较大的数字比较,找出较大值,若父节点较大,则跳出循环。若子节点较大,则父节点和子节点交换。
- 第三步:光标跳转至被交换子节点。
重复该过程,即可得到新数组
代码入下:
/*
arr: 目标数组
index: 目标节点
size: 数组大小监测
*/
void HeapIfy(int *arr, int index, int size)
{
int left = index * 2 + 1;
while (left < size)
{
//找较大子节点
int largest = (left + 1 < size && arr[left + 1] > arr[left]) ? left + 1 : left;
//比较子节点和父节点
if (arr[largest] > arr[index])
Swap(arr, largest, index);
else
break;
//循环结构
index = largest;
left = index * 2 + 1;
}
}
堆排序:
- 堆排序的实质就是调用上述两种方法
- 先将数据全部写入二叉树;
- 取出头节点的值(最大值),将这个最大值与数组最后一位交换,这样最大值就排在了最后一位,光标前移,不再将最后一位算入堆结构中;
- 排除最后一位的元素,对前size - 1位进行HeapIfy(中间插入向下比较),得到新的顺序;
- 重复这个操作,当size == 0即可依次得到排序后的数组;
第一次交换:
排序后:
第二次交换:
依次执行即可实现排序操作。
具体方法实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <windows.h>
void Swap(int *arr, int x, int y)
{
int temp = 0;
temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
void HeapInsert(int *arr, int index)
{
while (arr[index] > arr[(index - 1) / 2])
{
//交换函数swap
Swap(arr, index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
/*
arr: 目标数组
index: 目标节点
size: 数组大小监测
*/
void HeapIfy(int *arr, int index, int size)
{
int left = index * 2 + 1;
while (left < size)
{
//找较大子节点
int largest = (left + 1 < size && arr[left + 1] > arr[left]) ? left + 1 : left;
//比较子节点和父节点
if (arr[largest] > arr[index])
Swap(arr, largest, index);
else
break;
//循环结构
index = largest;
left = index * 2 + 1;
}
}
void HeapSort(int* arr, int size)
{
int i = 0;
if (arr == NULL || size < 2)
return;
//进二叉树:
for (i = 1; i < size; i++)
{
HeapInsert(arr, i);
}
//排序:
while (size > 0)
{
Swap(arr, 0, --size);
HeapIfy(arr, 0, size);
}
}
int main()
{
int arr[] = { 2, 3, 1, 3, 4, 5, 2, 8, 4, 7, 0, 8, 9, 3, 1 };
int size = sizeof(arr) / sizeof(arr[0]);
HeapSort(arr, size);
for (int i = 0; i < size; i++)
{
printf("%d ", arr[i]);
}
system("pause");
return 0;
}
最后
以上就是愤怒母鸡为你收集整理的C语言实现堆排序堆排序原理: 堆排序:的全部内容,希望文章能够帮你解决C语言实现堆排序堆排序原理: 堆排序:所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复