堆的特性是父节点的值总是大于(大根堆)或者总是小于(小根堆)其子节点的值。堆的应用场景就是,优先级队列。
利用堆进行排序步骤
- heap_sort.hpp
#ifndef HEAP_SORT_HPP
#define HEAP_SORT_HPP
#include <utility>
namespace base
{
struct heap_sort
{
private:
/*!
* 这个一个从底向上的一个过程,逐步的完成。
*/
template<typename Ite>
void construct_heap(Ite b, Ite e)
{
//由子节点的current_index 获取父节点的parent_index:
//计算公式 parent_index = (current_index-1)/2
auto get_parent_index =[](int current_index){
return static_cast<int>((current_index-1)/2);};
for(int i = 0; i < (e-b); ++i)
{
auto current_index = i; //当前节点
auto parent_index = get_parent_index(current_index); //父节点
while(*(b+current_index) > *(b+parent_index)) //当前节点的值大于父节点
{
//交换父子节点的值
std::swap(*(b+current_index), *(b+parent_index));
//将父节点的索引当作当前节点索引
current_index = parent_index;
//再次计算父节点的索引
parent_index = get_parent_index(current_index);
}
}
}
/*!
*这是一个从顶向下的过程,关键点是终止条件和选择子结点中最大的值,避免思考复杂度
*/
template<typename Ite>
void heapify(Ite b, Ite e)
{
//由父节点的parent_index 获取子节点的index:
//计算公式 left_child_index = 2 * parent_index+1
//计算公式 right_child_index = 2 * parent_index+2
auto get_left_child_index = [](int parent_index){return 2 * parent_index + 1;};
auto get_right_child_index = [](int parent_index){return 2 * parent_index + 2;};
int max_size = e - b;
auto current_index = 0;
auto left_child_index = get_left_child_index(current_index);
auto right_child_index = get_right_child_index(current_index);
while(left_child_index < max_size)
{
int max_child_index;
//获取左右节点之中最大的节点的索引
if(right_child_index < max_size &&
(*(b + left_child_index) < *(b+right_child_index)))
max_child_index = right_child_index;
else
max_child_index = left_child_index;
//终止条件,当前的值大于两个子节点的值
if(*(b+current_index) > *(b+max_child_index))
{
break;
}
//交换值
std::swap(*(b+current_index), *(b+max_child_index));
//再次下探,求索。
current_index = max_child_index;
left_child_index = get_left_child_index(current_index);
right_child_index = get_right_child_index(current_index);
}
}
public:
template<typename C_>
void operator()(C_& c)
{
//传进来的集合是空的
if(std::begin(c) == std::end(c))
return;
//1 构造成堆结构
construct_heap(std::begin(c), std::end(c));
auto b = std::begin(c);
auto e = std::end(c);
while(b != e)
{
//2 将堆的首尾交换,保留最右边的值不在参与重建堆
std::swap(*b, *(e-1));
--e; //3 缩小重建堆的范围
heapify(b,e); //4 重建堆 -> 2
}
}
};
}
#endif // HEAP_SORT_HPP
测试的结果:
#include <iostream>
#include <vector>
#include "heap_sort.hpp"
#include "basic_alg.h"
#include "executer.hpp"
using namespace std;
int main()
{
std::vector<int> v{1,9,7,4,3,5,8,6,2};
base::print_msg("Before sort: ", v);
base::executor<base::heap_sort>::exe(v);
base::print_msg("After sort: ", v);
return 0;
}