二叉堆是一颗完全二叉树,二叉堆中某个节点的值总是不大于(小于)其父节点的值,称为最大堆(最小堆),该实现从vector下标为0开始存储元素
最大堆实现:
// 利用vector存储实现堆,且从下标0位置开始存储元素
// parent(i) = (i-1)/2
// leftChild(i) = 2 * i + 1
// rightChild(i) = 2 * i + 2
// 最后一个非叶子节点索引为 (count-1) / 2, 其中 count 为当前堆中元素个数
template<typename T>
class MaxHeap_vector {
using uint = unsigned int;
public:
MaxHeap_vector() {
}
MaxHeap_vector(const T arr[], int n) {
// data.resize(n);
// memcpy(data.begin().base(), arr, n * sizeof(T));
data.assign(arr, arr + n);
count = n;
// 构建最大堆
for (int i = (count-1) / 2; i > 0; --i) {
shiftDown(i);
}
}
~MaxHeap_vector() {
data.clear();
data.shrink_to_fit();
}
void insert(T d) {
data.push_back(d);
++count;
shiftUp(count-1);
}
T popMax() {
if (count > 0) {
T res = data[0];
std::swap(data[0], data[count-1]);
--count; // 特别注意,在重新shiftDown之前,必须先减少元素,确保被移除
shiftDown(0);
return res;
}
std::cerr << "try to pop from empty heap" << std::endl;
return T();
}
void debugPrint() {
for (int i = 0; i < count; ++i) {
std::cout << data[i] << " ";
}
std::cout << std::endl;
}
private:
void shiftDown(uint i) {
uint k = i;
while (2 * k + 1 < count) {
uint j = 2 * k +1;
if ((j + 1 < count) && (data[j] < data[j + 1])) {
// 存在右子节点,且右子节点元素大于左子节点元素
++j;
}
if (data[k] < data[j]) {
// 父节点元素小于左右子节点元素最大者,则交换父子节点(保持最大堆性质),继续对该子节点进行shiftDown操作
std::swap(data[k], data[j]);
k = j;
continue;
}
break;
}
}
void shiftUp(uint i) {
uint k = i;
while (k > 0) {
int j = (k-1) / 2;
if (j > 0 && data[j] < data[k]) {
std::swap(data[j], data[k]);
k = j;
continue;
}
break;
}
}
private:
uint count = 0;
vector<T> data;
};
堆排序,利用该最大堆进行排序,注意,这里的堆排序利用了额外的空间,即堆得空间
void HeapSort_WithMaxHeapVector(int arr[], int n) {
HeapSpace::MaxHeap_vector<int> maxHeap_vector(arr, n); // 用待排序数组构造最大堆
for (int i = 0; i < n; ++i) {
arr[n - i - 1] = maxHeap_vector.popMax(); // 依次取出堆得最大元素用于排序
}
}
测试:
void MaxHeapVectorTest() {
int arr1[]{9, 3, 7, 6, 5, 1, 8, 2, 4};
int arr1r[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
HeapSort_WithMaxHeapVector(arr1, 9);
assert(SortCommon::ArrEqual(arr1, arr1r, 9) == true);
// 测试堆动态增加元素
int arr2[]{9, 3, 7, 6, 5, 1, 8, 2, 4};
HeapSpace::MaxHeap_vector<int> maxHeap_vector;
for(int v : arr2) {
maxHeap_vector.insert(v);
maxHeap_vector.debugPrint();
}
maxHeap_vector.debugPrint();
for(int i = 8; i>=0; --i) {
arr2[i] = maxHeap_vector.popMax();
}
assert(SortCommon::ArrEqual(arr2, arr1r, 9) == true);
return;
}