堆排序思路:
1、对传进来的数组, 进行堆调整(保证它是一个堆),即从倒数第一个根节点开始调整,例如长度为n,就从m = (n -1)/2 的位置开始向前调整。
2、具体堆调整规则Heapify(int * arr, int len, int m)//len 表示 arr 长度,m代表从第m个开始调整,以代码为例(建大根堆),找到根节点和子节点的最大值,并且把最大值交换给根节点,如果子节点比根节点大则继续向下调整。故堆调整时间复杂度为log(n),那么建堆的时间复杂度就是n*log(n)。
3、建堆结束后,使顶堆跟最后一个元素交换,这里 --i 达到弹出的效果,也就是i + 1到len-1的范围都是已经排好序的,再重新调整使符合大根堆,直到排序完毕
void Heapify(int* arr, int len, int m)//len 表示 arr 长度,m代表从第m个开始调整
{
if (m >= len)
{
return;
}
int left = m * 2 + 1;//找到左子节点
int right = m * 2 + 2;//找到右子节点
int max = m;
if (arr[left] > arr[max] && left < len)
max = left;
if (arr[right] > arr[max] && right < len)
max = right;
if (max != m)
{
swap(arr[max], arr[m]);
Heapify(arr, len, max);
}
}
void Heapify_build(int* arr, int len)//len 表示 arr 长度
{
//从倒数第一个根节点开始往前调整
int last_g_node = (len - 1) / 2;
for (int i = last_g_node; i >= 0; i--)
{
Heapify(arr, len, i);
}
}
void Heapify_Sort(int* arr, int len)//len 表示 arr 长度
{
Heapify_build(arr, len);//保证该数组是一个堆
for (int i = len - 1; i >= 0; i--)
{
swap(arr[0], arr[i]);//把第一个元素和第i个元素交换
Heapify(arr, i, 0);
}
}
void Test_heap()
{
int arr[] = { 4,5,3,8,7,9,6,1,0 };
int len = sizeof(arr) / sizeof(arr[0]);
Heapify_Sort(arr, len);
std::cout << std::endl;
for (int i = 0; i < len; i++)
{
std::cout << arr[i] << " ";
}
std::cout << std::endl;
}
4、算法分析
时间复杂度:
- 最好:O(n log n)
- 最坏:O(n log n)
- 平均:O(n log n)
空间复杂度:O(1)
稳定性:不稳定