• 堆是一棵完全二叉树,树中每个结点的值都不小于(或不大于)其左右孩子结点的值。

    堆一般使用优先队列(priority_queue)实现,而优先队列默认情况下使用的是大顶堆。

    堆的两个特性:

    1、结构性:用数组表示完全二叉树

    2、有序性:任一结点的关键词是其子树所有结点的最大值(或最小值)

      最大堆,也称“大顶堆”:父亲结点的值大于或等于结点的值

      最小堆,也称“小顶堆”:父亲结点的值小于或等于孩子结点的值

    注:从根节点到任意结点路径上结点序列的有序性!

    一、堆的存储:

    使用数组来存储完全二叉树,这样结点就按层序存储于数组中,其中第一个结点将存储于数组中的1号位,并且数组i号位表示的结点的左孩子就是2i号位,而右孩子则是(2i+1)号位。

    二、堆的基本操作:

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 0x3fffffff
    const int maxn=1010;
    //heap为堆,n为元素个数
    int heap[maxn],n=100;
    //向下调整  时间复杂度为O(logn)
    void downAjdust(int low,int high){
        int i=low,j=i*2;  //i为欲调整结点,j为其左孩子
        while(j<=high){ //存在孩子结点
            if(j+1<=high&&heap[j+1]>heap[j]){//如果存在右孩子结点,且右孩子的值大于左孩子
                j=j+1;      //让j存储右孩子的下标
            }
            if(heap[j]>heap[i]){    //如果孩子中最大权值比欲调整结点i大
                swap(heap[j],heap[i]);  //交换最大权值的孩子与欲调整结点i
                i=j;    //保持i为欲调整结点,j为i的左孩子
                j=i*2;
            }
            else{
                break;  //孩子的权值均比欲调整结点i小,调整结束
            }
        }
    }
    //建堆 时间复杂度O(n)
    void creatHeap(){
        for(int i=n/2;i>=1;i--){//从最后一个非叶子结点开始枚举
            downAdjust(i,n);
        }
    }
    //删除堆顶元素 时间复杂度O(logn)
    void deleteTop(){
        heap[1]=heap[n--];  //用最后一个元素覆盖堆顶元素,并让元素个数减 1
        downAdjust(1,n);    //向下调整堆顶元素
    }
    //向上调整   时间复杂度为O(logn)
    void upAdjust(int low,int high){//对heap数组在[low,high]范围进行向上调整,其中low一般设置为1
    //high表示欲调整结点的数组下标
        int i=high,j=i/2;//i为欲调整结点,j为其父亲
        while(j>=low){  //父亲在[low,high] 范围内
            if(heap[j]<heap[i]){    //父亲权值小于欲调整结点i的权值
                swap(heap[j],heap[i]);  //交换父亲和欲调整结点
                i=j;    //保持i为欲调整结点,j为i的父亲
                j=i/2;
            }
            else{
                break;  //父亲权值比欲调整结点i的权值大,调整结束
            }
            
        }
        
    }
    //添加元素   时间复杂度O(logn)
    void insert(int x){
        heap[++n]=x;    //让元素个数加 1 ,然后将数组末位赋值为 x
        upAdjust(1,n);  //向上调整新加入的结点 n
    }
    
    int main(){
        
        return 0;
    }

    堆排序:

    //堆排序    时间复杂度O(nlogn)
    void heapSort(){
        creatHeap();    //建堆
        for(int i=n;i>1;i--){   //倒着枚举,直到堆中只有一个元素
            swap(heap[i],heap[1]);  //交换heap[i]与堆顶
            downAdjust(1,i-1);  //向下调整堆顶
        }
    }

    堆排序完整代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 0x3fffffff
    const int maxn=1010;
    //heap为堆,n为元素个数
    int heap[maxn],n=100;
    //向下调整  时间复杂度为O(logn)
    void downAdjust(int low,int high){
        int i=low,j=i*2;  //i为欲调整结点,j为其左孩子
        while(j<=high){ //存在孩子结点
            if(j+1<=high&&heap[j+1]>heap[j]){//如果存在右孩子结点,且右孩子的值大于左孩子
                j=j+1;      //让j存储右孩子的下标
            }
            if(heap[j]>heap[i]){    //如果孩子中最大权值比欲调整结点i大
                swap(heap[j],heap[i]);  //交换最大权值的孩子与欲调整结点i
                i=j;    //保持i为欲调整结点,j为i的左孩子
                j=i*2;
            }
            else{
                break;  //孩子的权值均比欲调整结点i小,调整结束
            }
        }
    }
    //建堆 时间复杂度O(n)
    void creatHeap(){
        for(int i=n/2;i>=1;i--){//从最后一个非叶子结点开始枚举
            downAdjust(i,n);
        }
    }
    //删除堆顶元素 时间复杂度O(logn)
    void deleteTop(){
        heap[1]=heap[n--];  //用最后一个元素覆盖堆顶元素,并让元素个数减 1
        downAdjust(1,n);    //向下调整堆顶元素
    }
    //向上调整   时间复杂度为O(logn)
    void upAdjust(int low,int high){//对heap数组在[low,high]范围进行向上调整,其中low一般设置为1
    //high表示欲调整结点的数组下标
        int i=high,j=i/2;//i为欲调整结点,j为其父亲
        while(j>=low){  //父亲在[low,high] 范围内
            if(heap[j]<heap[i]){    //父亲权值小于欲调整结点i的权值
                swap(heap[j],heap[i]);  //交换父亲和欲调整结点
                i=j;    //保持i为欲调整结点,j为i的父亲
                j=i/2;
            }
            else{
                break;  //父亲权值比欲调整结点i的权值大,调整结束
            }
    
        }
    
    }
    //添加元素   时间复杂度O(logn)
    void insert(int x){
        heap[++n]=x;    //让元素个数加 1 ,然后将数组末位赋值为 x
        upAdjust(1,n);  //向上调整新加入的结点 n
    }
    //堆排序    时间复杂度O(nlogn)
    void heapSort(){
        creatHeap();    //建堆
        for(int i=n;i>1;i--){   //倒着枚举,直到堆中只有一个元素
            swap(heap[i],heap[1]);  //交换heap[i]与堆顶
            downAdjust(1,i-1);  //向下调整堆顶
        }
    }
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>heap[i];
        }
        heapSort();
        for(int i=1;i<=n;i++){
            cout<<heap[i]<<" ";
        }
        cout<<endl;
        return 0;
    }
    //示例:
    //5             输入
    //3 1 4 5 2     输入
    //1 2 3 4 5     输出
  • 相关阅读:
    LeetCode 面试题 08.02. 迷路的机器人
    LeetCode 96. 不同的二叉搜索树
    LeetCode 198 打家劫舍
    LeetCode 931 下降路径最小和
    Anaconda的安装及使用教程
    2020-8
    gdb与core dump
    实用linux命令
    offer_JZ25
    javaweb学习笔记整理补课
  • 原文地址:https://www.cnblogs.com/dreamzj/p/14615292.html
Copyright © 2020-2023  润新知