堆排序分为大顶堆排序和小顶堆排序,两者时间复杂度是O(nlogn),空间复杂度是O(1)的常量级临时变量,是不稳定排序算法。
大顶堆主要实现思想:
1.初始化构建大顶堆
void initMaxHeap(vector<int>& nums);
2.将大顶堆的根(最大值)交换到数组最后面,然后将待排序数组长度减一后重新构建大根堆
void buildMaxHeap(vector<int>& nums, int waitSortNode, int waitSortNums);
3.依次循环步骤2,直到待排序数组长度为0,完成大顶堆排序
for(int i=arr.size() - 1; i>0; --i) {swap(arr[0], [i]); buildMaxHeap(arr, 0, i);} // 经过初始化后的大顶堆基本有序,只需要将交换后的根节点依次向下找到合适位置即可
for (int i = nums.size() - 1; i > 0; --i) // 初始化完后最大值交换到数组最后面,然后对根节点待排序非叶子节点进行排序
{
std::swap(nums[0], nums[i]);
buildMaxHeap(nums, 0, i); // 这里只有根节点是需要排序的,因为前面已经初始化过大顶堆,是基本有序的,只有交换后的根节点是需要排序
}
注意:大顶堆每一个子节点都是一个大顶堆,所以交换后一定要重建大顶堆,将交换后的值摆放到合适位置
下面是实现选择排序算法代码
Sorts.h
#pragma once
#include <iostream>
#include <vector>
using namespace std;
struct Sorts {
void maxHeap(vector<int>& nums);
void print(vector<int>& nums);
private:
void buildMaxHeap(vector<int>& nums, int waitSortNode, int waitSortNums);
void initMaxHeap(vector<int>& nums);
};
Sorts.cpp
#include "Sorts.h"
void Sorts::maxHeap(vector<int>& nums)
{
initMaxHeap(nums); // 初始化大顶堆
for (int i = nums.size() - 1; i > 0; --i) // 初始化完后最大值交换到数组最后面,然后对根节点待排序非叶子节点进行排序
{
std::swap(nums[0], nums[i]);
buildMaxHeap(nums, 0, i); // 这里只有根节点是需要排序的,因为前面已经初始化过大顶堆,是基本有序的,只有交换后的根节点是需要排序
}
}
void Sorts::print(vector<int>& nums)
{
for (const auto& it : nums)
cout << it << ",";
cout << endl;
}
void Sorts::buildMaxHeap(vector<int>& nums, int waitSortNode, int waitSortNums)
{
int leftIndex = 2 * waitSortNode + 1;
int rightIndex = leftIndex + 1;
int maxIndex = waitSortNode; // 最小二叉树中最大值下标
if (leftIndex < waitSortNums && nums[maxIndex] < nums[leftIndex]) // 左子节点在待排序数组内才比较
maxIndex = leftIndex;
if (rightIndex < waitSortNums && nums[maxIndex] < nums[rightIndex]) // 右子节点在待排序数组内才比较
maxIndex = rightIndex;
if (maxIndex != waitSortNode) // 如果根节点不是最大值,则交换,交换后在进行自身子节点大根堆排序
{
std::swap(nums[maxIndex], nums[waitSortNode]);
buildMaxHeap(nums, maxIndex, waitSortNums);
}
}
void Sorts::initMaxHeap(vector<int>& nums)
{
// 从完全二叉树的最后一个非叶子依次比较,如果交换则保证交换后的子节点满足大顶堆性质
for (int i = nums.size()/2 - 1; i >= 0; --i)
buildMaxHeap(nums, i, nums.size()); // 剩余大小主要作用是判断节点子节点是否在待排序的数组里(i<waitSortNums)
}
main.cpp
#include <vector>
#include "Sorts.h"
using namespace std;
int main()
{
vector<int> nums = { 2,0,1,6,8,10,5,99,87,333,2,0,1 };
Sorts sorts;
sorts.print(nums);
sorts.maxHeap(nums);
sorts.print(nums);
return 1;
}
输出结果: