• 【总结】二叉堆


    简单介绍

    最小堆:最小堆是一个关键码序列{K1,K2,…,Kn},它具有如下特性:

    K[i] <= K[2i]

    K[i] <= K[2i+1]

    类似可以定义最大堆。

    性质

    完全二叉树的层次序列,可以用数组表示。

    堆中储存的数是局部有序的,堆不唯一。

    ​ 节点的值与其孩子的值之间存在限制。

    ​ 任何一个节点与其兄弟之间都没有直接的限制。

    从逻辑角度看,堆实际上是一种树形结构。

    基本操作

    top

    直接返回根结点

    时间复杂度O(1)

    pop

    弹出当前的最小值

    删掉根节点将最下面的节点放到根节点的位置

    再把根节点下传

    void pop()
    {
    	cout << "pop" << endl;
    	heap[1] = heap[n]; n--; downdate(1); //直接删除堆顶,把最后一个元素放到堆顶,下滤 
    	//print();
    }
    void downdate(int x){
    	while(x*2<=n){
    		int y=x*2;
    		if(x*2<n&&heap[x*2+1]<heap[x*2]){
    			y=x*2+1;
    		}
    		if(heap[x]<=heap[y])break;
    		swap(heap[x],heap[y]);
    		x=y;
    	}
    } 
    

    push

    插入一个数

    插入到后的位置,与它的父亲节点比较,进行上传

    void insert(int x){
    	heap[++n]=x;
    	update(n);
    
    }
    void update(int x){//上滤操作qwq 
    	while(x!=1){
    		if(heap[x/2]<=heap[x])break;
    		swap(heap[x/2],heap[x]);
    		x/=2;
    	}
    }
    

    stl

    priority_queue相当于一个堆,其实平时用的比较多的也是stl中的堆emm

    定义:priority_queue a;

    插入队尾:a.push(x);

    删除队首:a.pop();

    查询队首:a.top();

    清空只能慢慢pop。

    例题:序列合并

    详细解释看题解:传送门

    分析

    固定 A[i], 每 n 个和都是有序的:

    A[1] + B[1] <= A[1] + B[2] <= … <= A[1] + B[n]

    A[2] + B[1] <= A[2] + B[2] <= … <= A[2] + B[n]

    A[n] + B[1] <= A[n] + B[2] <= … <= A[n] + B[n]

    每次只需要考虑第一行第一个还未考虑的数即可

    例题:丑数

    丑数是指质因子在集合 {2, 3, 5, 7} 内的整数,第一个丑数是 1.

    现在输入 n,输出第 n 大的丑数。

    n <= 10000.

    分析

    与上一个题是非常非常相似的,唯一的不同在与上一个题是二元组,而我们现在考虑的是一个四元组

    用四元组(a, b, c, d)表示 2a3b5c7d,1就是 (0, 0, 0, 0)

    用最小堆存 2a3b5c7d ,每次取出最小值 (a, b, c, d)。

    然后把 (a + 1, b, c, d) (a, b + 1, c, d) (a, b, c + 1, d) (a, b, c, d + 1) 插入堆中。

    注意堆顶元素如果和上一个输出的数相等就需要 pop 掉。

  • 相关阅读:
    多线程(5)async&await
    多线程(4)Task
    多线程(3)ThreadPool
    多线程(2)Thread
    多线程(1)认识多线程
    泛型
    反射(4)反射性能问题:直接调用vs反射调用
    反射(3)反射应用:一个插件项目
    反射(2)使用反射
    反射(1)认识反射
  • 原文地址:https://www.cnblogs.com/huixinxinw/p/12242339.html
Copyright © 2020-2023  润新知