堆
堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。因此分为大根堆与小跟堆。
大根堆:升序
非叶子节点值大于等于左右子节点值: &&
小根堆:降序
非叶子节点值小于等于左右子节点值: &&
堆排序:
思路:
1、构造n个数值的大根堆或小根堆
2、将堆顶(最大或最小值),放至堆尾
3、继续构造前n-1个数值,n = n-1 转1,如此循环
4、输出 升序或降序 序列
算法(大根堆) i:根结点 2i:左节点 2i+1:右节点
1、从非叶子节点开始调整 n/2
2、在第2i个节点和第2i+1个节点中(左右节点)选最大值为X
3、若第i个节点(根)小于X则二者交换
4、交换后还需考虑以2i为根或2i+1为根的子树是否仍是堆,如不是则需要继续向下调整。
5、 1~4 循环至堆顶为最大值
6、堆顶堆尾交换元素,最大值放置最后。前 n - 1 继续调整,转 1; n == 0 结束
注:图像不清晰,资源有上传视频:堆排序-CSDN直播
代码
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
//<:升序,大根堆, >:降序,小根堆
#define cmp <
typedef int Node;
void printHeap(vector<int>& heap){
for(auto i: heap){
cout << i << " ";
}
cout << endl;
}
void nodeAdjust(vector<Node>& tree, Node root, int size){
int swapNode = root;
//左右节点
Node leftNode = root * 2 + 1;
Node rightNode = root * 2 + 2;
//叶子节点无需调整
if(root > size/2-1 ) return;
//左右节点与根结点进行比较,找极大或极小值
if(leftNode < size && tree[swapNode] cmp tree[leftNode])
swapNode = leftNode;
if(rightNode < size && tree[swapNode] cmp tree[rightNode])
swapNode = rightNode;
if( tree[root] cmp tree[swapNode] ){
//交换节点
swap(tree[root], tree[swapNode]);
//子节点被调整,则对应的子树堆被破坏需要重新调整
nodeAdjust(tree, swapNode, size);
}
}
//对于每个非叶子节点都进行调整,从后往前
void heapAdjust(vector<Node>& tree, int size){
for(int i = size/2-1; i >= 0; i --){
nodeAdjust(tree, i, size);
}
}
void heapSort(vector<int>& heap, int size){
for(int i = 0; i < size; i++){
//调整堆
heapAdjust(heap, size - i);
//将极值放最后
swap(heap[0], heap[size - 1 - i ]);
}
}
int main(){
vector<int> tree = {2, 4, 1, 3, 6};
heapSort(tree, tree.size());
printHeap(tree);
}