数据结构之堆

数据结构之堆

介绍

优先级队列,又叫堆,是一个完全二叉树,其中每个节点的值总是大于(小于)或者等于子节点的值,所以就有大顶堆和小顶堆。一般树的实现都是用结点连接而成,也即使用指针,但是因为堆是一个完全二叉树,所以使用数组来表示更方便,从数组下标0开始,位置为i的结点其父节点位置一定是(i-1)/2,而它两个子节点的位置一定是2i+1,2i+2。

堆的实现

插入元素
在堆中插入元素,一般是插入到数组的最后一个位置,然后开始上浮调整,插入元素之前默认堆已经建好了,我们以大顶堆为例子。

//插入元素
void inSert(vector<int>&arr,int data){
    arr.push_back(data);//将数据插入到数组末尾,然后开始上浮调整
    swim(arr,arr.size()-1);//然后开始上浮调整
}
//元素上浮调整,此时默认其他元素已经组成了大顶堆
void swim(vector<int>&7arr,int start){
   int c=start;//当前结点所处的位置,这里是数组最后一个元素的位置
   int p=(c-1)/2;//其父节点的位置
   int tmp=arr[c];//当前节点的元素值,后面单向赋值使用
   while(c>0){//从最后一个位置依次和其父节点比较,直到根节点
       if(tmp<=arr[p])break;//如果插入的元素值已经小于等于其父节点的值,说明已经有序了,已经满足堆的性质了
       else{//否则和父节点开始交换元素
          arr[c]=arr[p];//单向赋值即可,移动的是要插入的值,对要插入的值做出改变即可
          c=p;//索引改变,直接交换也可
          p=(p-1)/2;//同时父节点更新
       }
   }
   //将最终插入位置的值和要插入的元素的值交换
   arr[c]=tmp;//
}

删除元素
删除元素一般是删除堆顶的元素,可以直接将堆顶元素删除,然后再调正堆满足自身性质。这里使用数组最后一个元素直接放到堆顶,然后删除最后一个位置上的值和空间,再下沉这个元素调整堆。

    void reMove(vector<int>&arr,int data){
        arr[0]=arr.back();//已经是大顶堆,然后将最后一个元素赋值给堆顶,再调整即可
        arr.pop_back();//将最后一个元素从堆中剔除
        sink(arr,0,arr.size()-1);//下沉调整
    }
    //
        void sink(vector<int>&arr,int start,int end){
        int c=start;//当前节点的位置
        int l=2*c+1;//当前节点的左孩子节点的位置
        int tmp=arr[c];//当前节点的数值
        while(l<=end){//左闭右闭区间,
            if(l+1<=end&&arr[l]<arr[l+1]){//左右孩子中找到最大的,交换最大的,因为是大顶堆
                l++;//
            }
            if(tmp>=arr[l])break;//如果当前节点已经大于其左右孩子的最大值,就已经满足条件了
            else{//这里是单向赋值,一直修改父节点,到退出循环再把当前节点赋值。也可以直接swap,
                arr[c]=arr[l];//否则,左右孩子中最大的节点赋值给父节点,
                c=l;//更新下标
                l=2*l+1;//然后更新孩子节点,继续找下一个三角是否满足根节点最大
            }
        }
        arr[c]=tmp;//最后找到的位置,将当前节点的值更新
    }

堆的建立

    //构建,给一个无序的完全二叉树,然后将其构建成大顶堆。数组形式。
    //让所有非叶子节点下沉,不过是从非叶子节点下沉然后向上直到根节点,
    void buildMaxHeap(vector<int>&arr,int heapSize){
        for(int i=(heapSize+1)/2-1;i>=0;i--){//非叶子节点的计算,n/2-1.n是元素个数
            sink(arr,i,heapSize);//左闭右闭
        }
    }

STL之优先队列

    //堆STL使用,优先队列
    //priority_queue,每次只能访问位于队头的元素。
    //先进队列的不一定先出,而是优先级最大的元素先出队列。默认是大顶堆。
    //STL自定义排序 
    struct cmp{
        bool operator()(int a,int b){
            return a>b;//>对应greater,升序排列,小顶堆
        }
    };
    vector<int> stl_heapSort(vector<int>&arr){
        priority_queue<int,vector<int>,cmp>q(arr.begin(),arr.end());//
        //默认是大顶堆
        priority_queue<int,vector<int>,less<int>>;
        //也可改成小顶堆
        priority_queue<int,vector<int>,greater<int>>;
        int n=arr.size();
        vector<int>result;
        while(!q.empty()){//priority_queue没有迭代器,所以只能通过移除一个个元素来进行访问
            result.push_back(q.top());//普通队列是q.front();
            q.pop();
        }//STL中堆会自己调整
        //reverse(result.begin(),result.end());
        return result;
    }

堆排序

    //堆排序,建立的大顶堆只是堆顶元素最大,
    //依次将堆顶的元素移除放入数组,这里直接和最后一个元素交换就行,然后调整剩余的未排序的数组,之后重复交换堆顶和数组末尾元素
    //其实是移除堆顶元素,数组长度减一的操作,这里原地操作了,也可以用辅助数组来存储堆顶元素
    void heapSort(vector<int>&arr){
        int n=arr.size();
        buildMaxHeap(arr, n-1);//先构建堆,左闭右闭区间
        for(int i=n-1;i>=1;i--){//依次交换堆顶和数组尾部元素,这是数组最后一个元素就是最大值,依次类推,然后调整未排序的数组
            swap(arr[i],arr[0]);//交换
            sink(arr,0,i-1);//交换的堆顶元素是排好序的,调整剩下的未排序元素即可。依次类推
        }
    }

经典题目

  1. 第K个数
  2. 最小K个数

参考:leetcode

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值