堆排序算法就是在根节点与孩子节点比较大小,然后交换之前的值。堆排序利用来二叉树的性质,而这个树是一种特殊的树完成二叉树。堆排序分为大堆和小堆。
大堆定义:每个根节点的值都大于左孩子和右孩子的值。大堆排序是升序的,值是从小到大的排序方式
性质: array[i] > array[2 * i + 1] && array[i] > array[2 * i + 2]
小堆定义:每个根节点的值都小于左孩子和右孩子的值。小堆排序是降序的,值是从大到小的排序方式
性质 array[i] < array[2 * i + 1] && array[i] < array[2 * i + 2]
思路:
1、先构造大堆。
2、将顶堆元素与末尾元素进行交换
3、重复第二步骤,得到一个有序的数组。
void Head(int* arr, int i, int len) { // 记录当前i为最大值
int left_child = 2 * i + 1;
while (left_child < len) {
//建立大堆,若左孩子小于右孩子,取值为右孩子的下标,右孩子再与父结点比较
if (left_child + 1 < len && arr[left_child] < arr[left_child + 1]) {
left_child ++; // 在构建的时候确保左孩子小于右孩子,并取右孩子的下标
}
//将左右孩子中,数值最大的与父结点进行比较,若孩子结点比父结点小,说明父结点的数值比左右孩子都大,不需要交换
if (arr[i] > arr[left_child]) {
break; //说明该父结点和其孩子结点调整结束,退出循环,从下一个父结点调整
}
Swap(arr, i, left_child);
//交换之后,要考虑结点与自己的孩子结点的数值比较,还要进行调整,将当前父节点换成孩子结点所在位置
i = left_child;
left_child = 2 * i + 1;
}
}
void CreateHead(int *arr,int len) {
int i;
for(i = len / 2 - 1; i >= 0; i--) {
Head(arr, i, len);
}
}
void HeapSort(int* arr, int len) {
int i;
CreateHead(arr, len);
for (i = len - 1; i > 0; i--) { //进行n-1趟排序
Swap(arr, 0, i); // 跟与最后一个元素交换
// 对调整 自上而下
len --;
Head(arr, 0, len);
}
}
int main(int argc, char **argv)
{
int len = 10;
int array[10];
int i;
srand(time(NULL));
for (i = 0; i < len; i++) { // 采用随机数,参数数组的值。
array[i] = rand() / 100;
}
printf("Before sorting \r\n");
for (i = 0; i < len; i++) {
printf("%d ", array[i]);
}
printf("\r\n");
HeapSort(array, len);
printf("After sorting \r\n");
for (i = 0; i < len; i++) {
printf("%d ", array[i]);
}
return 0;
}
执行完毕之后的结果
对代码进行改进,利用三个数比较的原理,谁是最大的那个。
void Head(int* arr, int i, int len) {
int left_child = 2 * i + 1; // 左孩子
int right_child = 2 * i + 2; // 右孩子
int max = i; //将当前设置为最大得根节点
while ( left_child < len) {
if ( left_child < len && arr[left_child] > arr[max]) { // 将左孩子与根相比较,取最大的一个
max = left_child;
}
if ( right_child < len && arr[right_child] > arr[max]) { // 将右孩子与根相比较,取最大的一个
max = right_child;
}
if (arr[max] < arr[i]) { // 左右孩子有一个是最大的,在和根节点相比较取最大值。
i = max;
}
if (i == max) { // 若根节点为最大,说明已经满足大堆。
break;
}
Swap(arr, max, i); // 若根节点不是最大,则交换值
i = max;
// 要调整左右孩子的下标值
left_child = 2 * i + 1;
right_child = 2 * i + 2;
}
}