14.堆排序
堆排序
从 13 里面拿出来的,害,后面的数组就自己编把,别和我重了
代码
#include <iostream>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::ostream;
using std::string;
using std::swap;
struct Element
{
int key;
string data;
// 重载比较运算符, 方便后面直接元素对比
bool operator<(const Element &rhs) const { return key < rhs.key; }
bool operator<=(const Element &rhs) const { return key <= rhs.key; }
bool operator>(const Element &rhs) const { return key > rhs.key; }
bool operator>=(const Element &rhs) const { return key >= rhs.key; }
};
// 重载 << 用于输出数组类型
template <size_t N>
ostream &operator<<(ostream &os, const Element (&array)[N])
{
for (const Element &e : array)
cout << e.data << "(" << e.key << ") ";
return os;
}
// 把以 root 为根的子树调整为大根堆(根>=左、右孩子)
// 数组从 1 号位置开始放, root 的左孩子是 2*root, 右孩子是 2*root + 1
// 这里的数组从 0 号位置开始放, root 的左孩子是 2*root+1, 右孩子是 2*root + 2
void adjust_heap(Element array[], int root, int length)
{
Element old_root = array[root]; // 暂存 root 节点的值
for (int i = 2 * root + 1; i < length; i = 2 * i + 1) // i 指向 root 节点的左孩子
{
if (i + 1 < length && array[i] < array[i + 1]) // 如果右孩子存在, 且比左孩子大
i++; // 让 i 指向右孩子
if (old_root >= array[i])
break; // 如果原 root 结点的值 >= 左右孩子中的最大者, 不用调整了
array[root] = array[i]; // 否则, 把它换到 root 结点的位置
root = i; // 换过之后, 以 i 为根的子树可能不再是大根堆, 需要继续调整
}
array[root] = old_root; // 调整到最后, root 指到了正确位置, 它的父节点比它大, 子节点比它小, 原来的根节点就放到这里
}
// 建立一个大根堆
void build_max_heap(Element array[], int length)
{
int last_branch_node = length / 2; // 最后一个分支结点应该是 结点数 / 2, 往后就是叶子结点了
for (int i = last_branch_node; i >= 0; i--) // 从后往前, 调整所有分支结点
adjust_heap(array, i, length);
}
// 堆排序
void heap_sort(Element array[], int length)
{
build_max_heap(array, length); // 把数组转成大根堆
for (int i = length - 1; i > 0; i--) // 从数组最后一个元素开始往前扫
{
swap(array[0], array[i]); // 把大根堆的根节点(最大值)换到后面
adjust_heap(array, 0, i);
}
}
int main(int argc, char const *argv[])
{
Element array[] = {{23, "小红"}, {88, "小米"}, {6, "小黑"}, {54, "小白"}, {76, "小绿"}};
int length = 5;
cout << "原始数组: " << array << endl;
heap_sort(array, length);
cout << "排序结果: " << array << endl;
return 0;
}