【暖*墟】 #二叉堆# 大根堆的常见操作

一、二叉堆的定义

二叉堆使用完全二叉树(其前n-1层必须被填满,第n层也要从左到右顺序填满)来实现。

在二叉堆中,所有非终端结点的值均不大于(或不小于)其左右孩子的值。

非终端结点的值均不大于其左右孩子结点的值,这样的二叉堆叫做小根堆(下图b),

小根堆根结点的值是该堆中所有结点的最小值;

同样的,若非终端结点的值都不小于其左右孩子的值,这样的堆叫做大根堆(下图a),

大根堆根结点的值为改堆所有结点的最大值。利用堆的此性质,可以实现堆排序。

说明:小根堆和大根堆的实现没有太大的区别,所以下面以大根堆为例。

二、二叉堆的操作

堆一般使用数组来构建,假设为数组a[],结点通常存储在a[1],

这样对于下标为k的结点a[k]来说,其左孩子的下标为2*k,右孩子的下标为2*k+1

1、插入结点到堆中

结点插入的位置应该是完全二叉树的最后一个位置(如下图所示),

对于大根堆来讲,需要满足两个性质:

(1)堆为完全二叉树;(2)堆中每个父结点的值都不小于其左右子结点的值。

插入结点可能会破坏这两条性质,所以在插入结点后需要对堆进行调整。

调整方法为:将插入的结点与其父结点比较,若大于其父结点的值,则交换两者。

重复此操作,直至该结点不比其父结点大,或者该结点成为根结点。

可以通过插入结点到一个已经存在的堆中,也可以通过不断插入结点来构建一个堆

//insert
int heap[maxn],n;
void up(int p){ //通过交换位置p实现向上调整
    while(p>1){ //没有到达根节点
        if(heap[p]>heap[p/2]){
            swap(heap[p],heap[p/2]);
            p/=2; //编号变小:(2n+1)/2=2n/2=n。
        }
        else break; //找到位置,退出循环
    }
}
void insert(int val){
    heap[++n]=val; up(n); //放在底端,记录价值
}

↓↓↓GetTop:返回堆顶权值

//gettop
int gettop(){
    return heap[1];
}

2、删除堆顶元素(堆排序)

删除堆顶元素(根结点)后,会得到左右两棵子树,此时将堆中最后一个元素移到堆顶

然后自上而下调整,将该结点与左右孩子结点比较,此时会有三种情况:

(1)结点的左右孩子均为空,此时调整结束

(2)结点只有左孩子,将该结点与左比较。若结点小于其左孩子,则两者交换,否则调整结束;

(3)结点左右孩子都非空,则将该结点与左右较小者比较,若小于则交换,否则调整结束;

重复此过程,直到该结点不小于其左右孩子结点,或者该结点为叶子结点。

//extract
//删除堆顶元素,将末尾元素放到堆顶位置,再调整
void down(int p){ //向下调整
    int s=p*2; //p的左子节点
    while(s<=n){ //还没成为叶子结点
        if(s<n&&heap[s]<heap[s+1]) s++; //取左右节点较大值
        if(heap[s]>heap[p]){
            swap(heap[s],heap[p]);
            p=s,s=p*2; //现在位置变成s,子节点s相应改变
        }
        else break;
    }
}
void extract(){
    heap[1]=heap[n--]; //n处元素放在堆顶,n--
    down(1);
}

3、删除p处元素

//remove(p)

void up(int p){ //通过交换位置,实现向上调整
    while(p>1){ //没有到达根节点
        if(heap[p]>heap[p/2]){
            swap(heap[p],heap[p/2]);
            p/=2; //编号变小:(2n+1)/2=2n/2=n。
        }
        else break; //找到位置,退出循环
    }
}

void down(int p){ //向下调整
    int s=p*2; //p的左子节点
    while(s<=n){ //还没到末尾
        if(s<n&&heap[s]<heap[s+1]) s++; //取左右节点较大值
        if(heap[s]>heap[p]){
            swap(heap[s],heap[p]);
            p=s,s=p*2; //现在位置变成s,子节点s相应改变
        }
        else break;
    }
}

void remove(int p){
    heap[p]=heap[n--]; //n处元素放在k处,n--
    up(p); down(p); //可能向上或者向下调整
}

三.stl中的优先队列

priority_queue实现了一个大根堆。

支持 push(i),top(),pop()操作,不支持 remove 操作。

priority_queue<int> xxx 大根堆

priority_queue<int, vector<int>, greater<int>> xxxx 小根堆

//注意,多重符号时中间要打空格分隔符,否则‘>>’会影响。

——时间划过风的轨迹,那个少年,还在等你。

原文地址:https://www.cnblogs.com/FloraLOVERyuuji/p/9346754.html

时间: 2024-08-29 08:30:04

【暖*墟】 #二叉堆# 大根堆的常见操作的相关文章

二叉平衡树的插入和删除操作

1.      二叉平衡树 二叉排序树的时间复杂度和树的深度n有关.当先后插入的结点按关键字有序时,二叉排序树退化为单枝树,平均查找长度为(n+1)/2,查找效率比较低.提高查找效率,关键在于最大限度地降低树的深度n.因此需要在构成二叉排序树的过程中进行“平衡化”处理,使之成为二叉平衡树. 二叉平衡树,又称AVL树.它或者是一棵空树,或者是具有下列性质的树: 1)      具备二叉排序树的所有性质: 2)      左子树和右子树深度差的绝对值不超过1: 3)      左子树和右子树都是二叉

bzoj 1577: [Usaco2009 Feb]庙会捷运Fair Shuttle——小根堆+大根堆+贪心

Description 公交车一共经过N(1<=N<=20000)个站点,从站点1一直驶到站点N.K(1<=K<=50000)群奶牛希望搭乘这辆公交车.第i群牛一共有Mi(1<=Mi<=N)只. 他们希望从Si到Ei去.公交车只能座C(1<=C<=100)只奶牛.而且不走重复路线,请计算这辆车最多能满足多少奶牛听要求.注意:对于每一群奶牛,可以部分满足,也可以全部满足,也可以全部不满足. Input 第1行: 三个整数: K,N,C. 由空格隔开. 第2..

基本数据结构——二叉堆

迅速补档,为A*做一下铺垫… 概念定义 二叉堆就是一个支持插入.删除.查询最值的数据结构.他其实是一棵完全二叉树.那么堆一般分为大根堆和小根堆 大根堆 树中的任意一个节点的权值都小于或者等于其父节点的权值,则称该二叉树满足大根堆性质. 小根堆 树中的任意一个节点的权值都大于或者等于其父节点的权值,则称该二叉树满足小根堆性质. 习惯用法 一般习惯把堆用数组保存.才用父子二倍的编号方式.即:对于某一个节点x,其左儿子节点为2*x,右儿子节点为x*2+1 支持功能及代码实现 Insert插入 向二叉堆

Java数据结构之二叉搜索树

Java数据结构之二叉搜索树 1.二叉搜索树组成 二叉搜索树又称为二叉排序树,它或者是一颗空树,或者是一颗具有如下特性的非空二叉树,需要满足一下三个条件: (1)若它的左子树非空,则左子树上所有结点的关键字均小于根结点的关键字: (2)若它的右子树非空,则右子树上所有结点的关键字均大于(可以等于)根结点的关键字. (3)左子树右子树本身又各是一颗二叉搜索树 在算法描述中,均以结点值的比较来代表其关键字的比较,因为若结点的值为类类型时,该类必须实现系统提供的java.lang.comparable

C++实现二叉搜索树的常用操作

实现操作 (1)二叉搜索树的建立 (2)二叉搜索树的插入 (3)二叉搜索树的三种递归遍历(前序.中序和后续) (4)二叉搜索树的三种非递归遍历(前序.中序和后续) (5)二叉搜索树的逐层打印 (6)搜索某一个字符(递归算法) (7)搜索一个字符(非递归算法) (8)查找最大元素 (9)查找最小元素 有时间再实现: (10)二叉搜索树的前驱和后继查找 (11)二叉搜索树的删除 源码分析: #include <iostream> #include <stack> #include &l

二叉搜索树转化为双向链表

1. 题目 输入一棵二叉搜索树,现在要将该二叉搜索树转换成一个排序的双向链表.而且在转换的过程中,不能创建任何新的结点,只能调整树中的结点指针的指向来实现. 二叉树结点的定义如下: struct BinaryTreeNode { intm_nValue; BinaryTreeNode*m_pLeft; BinaryTreeNode*m_pRight; }; 如图1-1(a)为一棵二叉搜索树,1-1(b)为对应的双向链表. 图1-1转化示意图 2. 分析 (1) 二叉搜索树中序遍历可得有序的结点序

【数据结构第四周】树知识点整理(下)【二叉搜索树】

二叉搜索树 (1)定义 二叉搜索树(Binary Search Tree),也称二叉排序树或二叉查找树 一棵二叉树,可以为空:如果不为空,满足以下性质: a.非空左子树的所有键值小于其根节点的键值 b.非空右子树的所有键值大于其根节点的键值 c.左右子树都是二叉搜索树 (2)相关操作 Position Find( ElementType X, BinTree BST ):从二叉搜索树BST 中查找元素X,返回其所在结点的地址 Position FindMin( BinTree BST ):从二叉

二叉搜索树JavaScript实现

* 什么是二叉搜索树?其形式就是二叉树,对于每个节点x,其左子树的值<=x.value,右子树的值>=x.value. * 对于二叉搜索树,我们可以使用中序遍历,得到树上从小到大所有的元素.时间复杂度平均为O(n). function inorderTreeWalk(x) { if(x!== null) { inorderTreeWalk(x.left); print(x.key); inorderTreeWalk(x.right); } } * 当我们想要查询二叉搜索树中某个关键字应该怎么做

4-12 二叉搜索树的操作集 (30分)

本题要求实现给定二叉搜索树的5种常用操作. 函数接口定义: BinTree Insert( BinTree BST, ElementType X ); BinTree Delete( BinTree BST, ElementType X ); Position Find( BinTree BST, ElementType X ); Position FindMin( BinTree BST ); Position FindMax( BinTree BST ); 其中BinTree结构定义如下: