堆排序(递归)C++实现
堆排序
使用堆的数据结构来进行排序,堆可以看成一个近似完全二叉树的顺序存储结构的数组
维护堆性质
维护堆的性质,对于给定的下标i
,以i
结点为根节点的堆左右子树都是最大堆,此时i
对应结点的关键字可能小于其孩子节点,则违背了堆性质,通过向下调整使得这个堆满足最大堆的性质
堆调整算法选取根节点左右孩子关键字较大值与根节点交换,再递归进入被交换的左右孩子为根节点的堆,继续向下调整,直到当前的堆满足最大堆性质或者调整到叶子节点。
- C++代码
void MaxHeap::maxHeapify(int i) {
int leftChild = left(i);
int rightChild = right(i);
int largest = i;
if (leftChild <= heapSize && sequence[leftChild] > sequence[largest]) {
largest = leftChild;
}
if (rightChild <= heapSize && sequence[rightChild] > sequence[largest]) {
largest = rightChild;
}
if (largest != i) {
// 选取左右孩子结点关键字较大的与根节点交换
swap(sequence[i], sequence[largest]);
// 递归进入被调整的子树对应的堆继续向下调整
maxHeapify(largest);
}
}
- 伪代码
MAX-HEAPIFY(A, i)
l = LEFT(i)
r = RIGHT(i)
if l <= A.heap-size and A[l] > A[i]
largetest = l
else largetest = i
if r <= A.heap-size and A[r] > A[largetest]
largetest = r
if largetest != i
exchange A[i] with A[largetest]
MAX-HEAPIFY(A, largetest)
建堆
从倒数第二层开始向下调整,因为最后一层的堆只有一个结点必然满足堆性质,而第二层调整完毕后,保证以倒数第二层结点为根结点的堆满足堆性质,继续调整倒数第三层直到调整到第一层的根节点,即整个堆满足堆性质,建堆完成。
- C++代码
void MaxHeap::buildMaxHeap() {
for (int i = heapSize / 2; i > 0; i--) {
maxHeapify(i);
}
}
- 伪代码
BUILD-MAX-HEAP(A)
A.heap-size = A.length
for i = [A.length / 2] downto 1
MAX-HEAPIFY(A, i)
堆排序
根据堆性质,堆顶元素(根结点)必然为堆中最大,每次堆顶元素与堆最后一个元素交换,即每次都取出子序列的最大值,这样能够保证堆为空后,所得到的序列为非递减序列,但每次交换操作后需要维护堆性质,才能保证下一次要取出的堆顶元素满足要求
- C++代码
void MaxHeap::heapSort() {
buildMaxHeap();
for (int i = heapSize; i > 1; i--) {
swap(sequence[i], sequence[1]);
heapSize--;
maxHeapify(1);
}
}
- 伪代码
HEAPSORT(A)
BUILD-MAX-HEAP(A)
for i = A.length downto 2
exchange A[1] with A[i]
A.heap-size = A.heap-size - 1
MAX-HEAPIFY(A, 1)
实现代码
/*
author : eclipse
email : eclipsecs@qq.com
time : Wed Jul 15 20:37:52 2020
*/
#include <bits/stdc++.h>
using namespace std;
class MaxHeap {
private:
vector<int> sequence;
int heapSize;
void maxHeapify(int i);
int parent(int i);
int left(int i);
int right(int i);
void buildMaxHeap();
public:
MaxHeap(vector<int> array);
void heapSort();
void traverse();
};
MaxHeap::MaxHeap(vector<int> array) {
heapSize = array.size();
sequence.resize(array.size() + 1);
for (int i = 1; i < sequence.size(); i++) {
sequence[i] = array[i - 1];
}
}
int MaxHeap::parent(int i) {
return i / 2;
}
int MaxHeap::left(int i) {
return i * 2;
}
int MaxHeap::right(int i) {
return i * 2 + 1;
}
void MaxHeap::maxHeapify(int i) {
int leftChild = left(i);
int rightChild = right(i);
int largest = i;
if (leftChild <= heapSize && sequence[leftChild] > sequence[largest]) {
largest = leftChild;
}
if (rightChild <= heapSize && sequence[rightChild] > sequence[largest]) {
largest = rightChild;
}
if (largest != i) {
swap(sequence[i], sequence[largest]);
maxHeapify(largest);
}
}
void MaxHeap::buildMaxHeap() {
for (int i = heapSize / 2; i > 0; i--) {
maxHeapify(i);
}
}
void MaxHeap::heapSort() {
buildMaxHeap();
for (int i = heapSize; i > 1; i--) {
swap(sequence[i], sequence[1]);
heapSize--;
maxHeapify(1);
}
}
void MaxHeap::traverse() {
for (int i = 1; i < sequence.size(); i++) {
printf("%d ", sequence[i]);
}
}
int main(int argc, char const *argv[]) {
vector<int> array;
int N;
scanf("%d", &N);
array.resize(N);
for (vector<int>::iterator it = array.begin(); it != array.end(); it++) {
scanf("%d", it);
}
MaxHeap *maxHeap = new MaxHeap(array);
maxHeap->heapSort();
maxHeap->traverse();
return 0;
}
测试数据
10
2 0 2 0 0 7 1 5 21 34
输出结果
0 0 0 1 2 2 5 7 21 34
鸣谢
最后
- 上述伪代码来自算法导论
- 由于博主水平有限,不免有疏漏之处,欢迎读者随时批评指正,以免造成不必要的误解!