【排序】——堆排序

堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。因此分为大根堆与小跟堆。

大根堆:升序

非叶子节点值大于等于左右子节点值:i \geq 2i && i \geq 2i+1

小根堆:降序

非叶子节点值小于等于左右子节点值:i \leq 2i && i \leq 2i +1

 堆排序:

思路:

        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);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值