程序猿面试之堆排序C++实现

程序猿面试之 堆排序 C++
堆是一颗完全二叉树,分为大顶堆和小顶堆:
大顶堆:每一个结点的值都大于其子节点
小顶堆:每一个结点的值都小于其子节点

堆排序分为两步:

  1. 将数组 vec 变为大顶堆,此时头结点 vec[0] 就是最大值
  2. 将头结点 vec[0] 和尾结点 vec[n-1] 交换,那么交换后,最大值就在尾部为vec[n-1];
  3. 将vec[0], vec[1], …, vec[n-2];重新构造为大顶堆;即将除去最后一个元素(最大值)的数组重建为大顶堆。此时堆顶vec[0]即为剩下的的元素中的最大值m。
  4. 将vec[0]和vec[n-2]交换,此时m就被换到vec[n-2];
  5. 不断的重建并交换,那么尾部的元素会被排序

堆排序关键是将最大的元素交换交换后的重建过程;这个过程被称为heapify;下面的程序中将其命名为MaxHeap.


    //移除index处的节点后堆的重建方法
    //index为需要调整的父节点下标,heapsize用来判断孩子是否越界;一开始的时候heapsize等于vec.size();而不是size -1;
    void MaxHeap(vector<int>&vec, int index, int heapsize) {
        //父亲下标
        int dad = index;
        //左孩子的下标; 右孩子下标left_son+1;
        int left_son = 2*dad+1;
        while(left_son < heapsize) {
            //左右孩子决出最大值的下标
            int largest = left_son +1 < heapsize && vec[left_son+1] > vec[left_son] ? left_son + 1: left_son;
            //父亲和最大孩子之间pk得出最大值
            largest = vec[largest] > vec[dad] ? largest:dad;
            //如果比较下来,父亲还是最大的,那么不用比了,因为父亲>孩子,孩子>孩子的孩子;所以不用比了,直接跳出;
            if(largest == dad) return;
            //如果父亲不是最大,那么还需要往下调整
            swap(vec[largest], vec[dad]);
            dad = largest;
            left_son = dad*2 +1;
        }

    }

    //排序主函数                                                                                             
    void HeapSort(vector<int>& vec) {
        if(vec.size() < 2) return;
        int heap_size = vec.size();
        
        //从最后一个父亲开始调整,把数组调整为堆
        for(int i = (heap_size -1)/2; i >= 0; i--) {
            MaxHeap(vec, i, heap_size);
        }

        //交换第一个和最后一个元素,并将堆减小 
        swap(vec[0],vec[--heap_size]);

        //不断的交换头结点并重建的过程
        while(heap_size > 0) {
            MaxHeap(vec, 0, heap_size);
            swap(vec[0],vec[--heap_size]);
        }
    }

调用示例

    #include<iostream>
    #include<vector>
    using namespace std;
   
    //移除index处的节点后堆的重建方法
    //index为需要调整的父节点下标,heapsize用来判断孩子是否越界;一开始的时候heapsize等于vec.size();而不是size -1;
    void MaxHeap(vector<int>&vec, int index, int heapsize) {
        //父亲下标
        int dad = index;
        //左孩子的下标; 右孩子下标left_son+1;
        int left_son = 2*dad+1;
        while(left_son < heapsize) {
            //左右孩子决出最大值的下标
            int largest = left_son +1 < heapsize && vec[left_son+1] > vec[left_son] ? left_son + 1: left_son;
            //父亲和最大孩子之间pk得出最大值
            largest = vec[largest] > vec[dad] ? largest:dad;
            //如果比较下来,父亲还是最大的,那么不用比了,因为父亲>孩子,孩子>孩子的孩子;所以不用比了,直接跳出;
            if(largest == dad) return;
            //如果父亲不是最大,那么还需要往下调整
            swap(vec[largest], vec[dad]);
            dad = largest;
            left_son = dad*2 +1;
        }

    }

    //排序主函数                                                                                             
    void HeapSort(vector<int>& vec) {
        if(vec.size() < 2) return;
        int heap_size = vec.size();
        
        for(int i = (heap_size -1)/2; i >= 0; i--) {
            MaxHeap(vec, i, heap_size);
        }

        //交换第一个和最后一个元素,并将堆减小 
        swap(vec[0],vec[--heap_size]);

        while(heap_size > 0) {
            MaxHeap(vec, 0, heap_size);
            swap(vec[0],vec[--heap_size]);
        }
    }   


    int main() {
        vector<int>vec = {3,25,6,2,7,35,25,6,36,3,4,7,8,3};
        HeapSort(vec);
        for(int i =0; i< vec.size(); i++) {
            std::cout<<vec[i]<<" ";
        }
        return 0;
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值