堆排序
堆排序算法思路
详细思路请参考《算法导论》堆排序一章,算法描述如下:
输入: 无序数组nums
输出: 有序数组nums
1. 使用heapSort()将无序数组nums建成最大堆
2. 从数组最后一个元素倒序遍历:i
1. 交换第一个元素和第i个元素的值
2. 去除堆的最后一个元素,将堆的长度-1
3. 调用maxHeapify()维护堆,使其重新为最大堆
4. 更新nums的值,使其从0到i-1为最大堆
3. 得到升序排列的数组nums
little tips
- 堆的思想虽然是完全二叉树,但实现上不需要采用树结构,使用数组的下表遍历即可。
- 对于下表从0开始的,第i个结点的左孩子是(2*i+1),右孩子是(2*i+2),父节点是floor((i-1)/2).
- 时间复杂度是O( nlog n),空间复杂度是O(1).
代码
// 堆排序
void heapSort(vector<int>& nums)
{
buildHeap(nums);
for(int i= nums.size()-1;i>= 1; i--)
{
std::swap(nums[0],nums[i]);
vector<int> nums_new(nums.begin(),nums.begin()+i);
maxHeapify(nums_new,0);
for (int j = 0; j < i; j++)
{
nums[j] = nums_new[j];
}
}
}
// 建最大堆
void buildHeap(vector<int>& nums)
{
if(nums.empty()) return;
int ind_lastMidnode = floor((nums.size()-1)/2);
for (int i = ind_lastMidnode; i >= 0; i--)
{
maxHeapify(nums,i);
}
}
//维护堆
void maxHeapify(vector<int>& nums,int i)// maintain the maximum heap
{
int left=2*i+1;
int right = 2*i +2;
int ind_max=i;
if(left <= nums.size() - 1 && nums[left] > nums[ind_max])
ind_max = left;
if(right <= nums.size() - 1 && nums[right] > nums[ind_max])
ind_max = right;
if(ind_max != i)
{
std::swap(nums[i],nums[ind_max]);
maxHeapify(nums,ind_max);
}
}