一、堆的重要操作
(1)向大根堆形态的完全二叉树中添加一个数到树的末尾,通过向上调整该数的位置,使得二叉树保持大根堆的形态。
//交换数组两元素位置
void swap(int* arr, int i, int j)
{
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
//某个数在index位置,往上继续移动
void heapInsert(int* arr, int index)
{
//当该数比它的父亲大时,可以向上移动
while (arr[index] > arr[(index - 1) / 2])
{
swap(arr, index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
(2)从大根堆形态的完全二叉树中移除一个数,并将大根堆末尾的数移动到空出的位置补充,通过向下调整补充数的位置,使得二叉树保持大根堆的形态。
//某个数在index位置,能否向下移动(将堆顶数移走,重新构建堆)
void heapify(int* arr, int index, int heapSize)
{
int left = index * 2 + 1;//左孩子的下标
while (left < heapSize)//当左孩子存在的时候
{
//两个孩子中,谁的值大,把下标给largest
int largest = left + 1 < heapSize && arr[left + 1] > arr[left] ? left + 1 : left;
//父亲和较大的孩子之间,谁的值大,把下标给largest
largest = arr[largest] > arr[index] ? largest : index;
if (largest == index)
break;
//否则交换堆顶index的值和孩子largest的值
swap(arr, largest, index);
index = largest;
left = index * 2 + 1;
}
}
(3)时间复杂度
上面两段代码的时间复杂度都是
二、堆排序
(1)思路
1.把无序数组构成大根堆(heapInsert函数),此时最大值被放在堆顶位置。
2.将堆顶数与堆底数(完全二叉树中最后面的数)交换位置,最大数被放在队尾并移出堆结构。
3.将得到的新堆重新构成大根堆(heapify函数),第二大的数被放在堆顶位置。
4.将堆顶数与堆底数(完全二叉树中最后面的数)交换位置,第二大的数被移出堆结构。
5.重复上述操作,直到所有数都被移出堆。
(2)代码实现
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
//交换数组两元素位置
void swap(int* arr, int i, int j)
{
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
//某个数在index位置,往上继续移动
void heapInsert(int* arr, int index)
{
//当该数比它的父亲大时,可以向上移动
while (arr[index] > arr[(index - 1) / 2])
{
swap(arr, index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
//某个数在index位置,能否向下移动(将堆顶数移走,重新构建堆)
void heapify(int* arr, int index, int heapSize)
{
int left = index * 2 + 1;//左孩子的下标
while (left < heapSize)//当左孩子存在的时候
{
//两个孩子中,谁的值大,把下标给largest
int largest = left + 1 < heapSize && arr[left + 1] > arr[left] ? left + 1 : left;
//父亲和较大的孩子之间,谁的值大,把下标给largest
largest = arr[largest] > arr[index] ? largest : index;
if (largest == index)
break;
//否则交换堆顶index的值和孩子largest的值
swap(arr, largest, index);
index = largest;
left = index * 2 + 1;
}
}
//堆排序
void heapSort(int* arr, int len)
{
if (arr == NULL || len < 2)
return;
for (int i = 0; i < len; i++)
{
heapInsert(arr, i);//使数组构成大根堆
}
int heapSize = len;
swap(arr, 0, --heapSize);
while (heapSize > 0)
{
heapify(arr, 0, heapSize);
swap(arr, 0, --heapSize);
}
}
int main()
{
int arr[] = { 2,5,3,6,4,1 };
int len = sizeof(arr) / sizeof(arr[0]);
heapSort(arr, len);
for (int k = 0; k < len; k++)
printf("%d ", arr[k]);
}
(3)时间复杂度和空间复杂度
时间复杂度为,上面两个重要操作的时间复杂度为,共执行N次。
额外空间复杂度为