二叉堆

Heapsort 和 priority queue

怎甘沉沦 提交于 2020-04-18 04:49:28
一、二叉堆含义及属性: 堆(heap)亦被称为:优先队列(priority queue),是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵完全二叉树的数组对象。在队列中,调度程序反复提取队列中第一个作业并运行,因而实际情况中某些时间较短的任务将等待很长时间才能结束,或者某些不短小,但具有重要性的作业,同样应当具有优先权。堆即为解决此类问题设计的一种数据结构。同垃圾收集存储的堆含义不同。 表示堆的数组A有两个属性: A.length : 代表A数组的元素个数; A.heapsize : 代表A数组中 属于堆元素个数。有时候(排序时),数组A的部分元素不属于堆。刚开始建堆的是偶,A.heapsize = A.length,排序时,每次从堆顶取出最大值,A.heapsize递减,直至排序完成. 下图是一个建好后的二叉堆: 从图中可知,已知某节点的索引值i,可以轻松获取其对应父节点,左,右子节点的索引值。有: Parent(i) return i/2; 或者 return i >> 1; Left(i) return i*2; 或者 return i << 1; Right(i) return i*2+1; 或者 return (i << 1) + 1; 二叉堆分两种: 最大堆,最小堆,均遵循堆属性。最大堆,每个节点i满足: A[Parent(i)] ≥ A[i]

二项堆

无人久伴 提交于 2020-03-03 16:49:24
目录 1.二叉堆(Binary Heap)、二项堆、斐波那契堆(简称Fib堆)的比较: 2. 二项树 2.1 定义 2.2 二项树B_k的性质 3. 二项堆 3.1 定义 3.2 数据结构 3.3 操作 3.3.1 五个基本操作 3.3.2 两个扩展操作 参考 @ 1.二叉堆(Binary Heap)、二项堆、斐波那契堆(简称Fib堆)的比较: 相同: 都是可归并堆(Mergeable Heap); 它们都支持5个基本操作(创建、插入、查找最小值、抽取最小值、合并堆)和2个扩展操作 (结点减值、结点删除)。 不同: 二叉堆是一种结点有序的完全二叉树,可采用数组结构存储,通过数组下标索引结点,分最大 堆和最小堆。 二项堆和Fib堆都是最小堆。 二项堆由二项树组成,结构比二叉堆复杂,但其堆合并操作的时间复杂度较好。当堆合并操作 较多时,可使用二项堆。反之,使用二叉堆即可。 2. 二项树 2.1 定义 仅包含一个结点的有序树是一棵二项树(B_0树)。二项树B_k由两棵B_{k-1}树组成,其中一 棵B_{k-1}树的根作为另一棵B_{k-1}树根的最左孩子(k≥0)。 2.2 二项树B_k的性质 结点数 n = 2{^k} 树高为 k = lgn 深度为i处有k!/(i!(k-i)!)个结点(k>=i>=0)。 根的度最大为k,若根的孩子从左到右编号为k-1,k-2,…,1,0

JUC源码分析-PriorityBlockingQueue

坚强是说给别人听的谎言 提交于 2020-02-25 18:10:03
概述 PriorityBlockingQueue:二叉堆结构优先级阻塞队列,FIFO,通过显式的lock锁保证线程安全,是一个线程安全的BlockingQueue,加入队列的数据实例按照指定优先级升序排列,这个规则通过赋值 实现了Comparator的字段或数据实例类实现Comparable接口自定义,都定义的情况下 字段比较器优先。它一个老牌的队列,在JDK1.5已经加入,如果队列加入的数据实例需要排序,这是个不错的选择。 核心属性和数据结构 private static final int DEFAULT_INITIAL_CAPACITY = 11;//默认数组容量 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//数组最大容量 private transient Object[] queue;//存储数据的数组 private transient int size;//节点数 统计用 private transient Comparator<? super E> comparator;//比较器,可自定义传入 private final ReentrantLock lock;//重入锁,依赖它实现线程安全 private final Condition notEmpty;//lock创建的

[数据结构与算法] 优先级队列/堆队列 完全二叉堆 左式堆 python里的heapq

≯℡__Kan透↙ 提交于 2020-02-25 15:23:07
学习 清华大学 尊敬的邓俊辉老师的C++数据结构与算法课程 第10章 优先级队列,本文旨在摘要和心得体会。 文章目录 1 优先级队列需求 2 完全二叉堆 2.1 定义 2.2 getMax() 2.3 insert() 插入与上滤 2.4 delMax() 删除与下滤 2.5 heapification 建堆 2.6 就地堆排序 3 左式堆 3.1 堆合并 3.2 左式堆 3.3 左式堆合并算法 3.4 左式堆 插入 3.5 左式堆 删除 4 python里的heapq 1 优先级队列需求 计算机系统里CPU的任务调度, 循 优 先 级 访 问 \color{red}{循优先级访问} 循 优 先 级 访 问 。 不同于队列结构的先进先出,找队列里最大值先出。 约定:优先级队列里的每个数据项目都有一个关键码key,可以进行比较大小(可依靠重载比较操作符实现),关键码越大,优先级越高。 操作接口描述: 操 作 接 口 功 能 描 述 size() 报告优先级队列的规模,即其中词条的总数 insert() 将指定词条插入优先级队列 getMax() 返回优先级最大的词条(若优先级队列非空) delMax() 删除优先级最大的词条(若优先级队列非空) 借助无序列表、有序列表、无序向量或有序向量,都难以同时兼顾insert()和 delMax()操作的高效率

左式堆的完整实现(含比较器,Java)描述

我的梦境 提交于 2020-02-24 03:55:30
引言 二叉堆是对优先队列的一种高效实现,左式堆是针对二叉堆合并操作困难的缺点,而提出的另外一种优先队列实现方式。 线性结构合并困难是显而易见的,而二叉堆那样高效的支持合并操作而且只使用一个数组更是难得。 这是因为,合并似乎需要把一个数组拷贝到另一个数组中去,对于相同大小的堆,这将花费O(N)。 但这区区O(N)还不够,所以就不能使用顺序存储结构,应该使用链式指针。有一句话说的特别好: 所有支持高效合并的高级数据结构都需要使用指针 。 能更高效完成合并的 左式堆 和 二项队列 显然都是使用了 指针 ,是 链接存储 的。 左式堆详解 这里有一篇比较详细的讲解,可看 从npl属性看左式堆 注意理解 npl 这个属性, npl 是 null path length 的缩写,意为 从该结点到达一个没有两个孩子的结点的最短距离 (一个孩子的结点或者叶子结点)。 一般定义 null 的 npl 为 -1 以使计算简便。 容易得到,任意结点的 npl 是它的子结点的 npl 中 较小 的那个结点的 npl+1 。 即 root.npl = min(root.left.npl, root.right.npl)+1 (前提是root != null && root.left != null && root.right != null,否则空指针……) 任意结点的左孩子的 npl 大于等于右孩子的

二叉堆学习笔记

断了今生、忘了曾经 提交于 2020-02-09 22:59:30
前言 其实这东西学过两年了……所以应该算是复习笔记吧? 定义 二叉堆,简称堆,顾名思义,是一棵二叉树,还是一棵完全二叉树。其显著特征是整棵树中父结点的值与子结点的值的大小关系都相同(即父结点的值均大于两个子结点的值或均小于两个子结点的值)。若大于,称之为大根堆,小于则是小根堆。显而易见,堆顶元素(即根节点)为二叉堆的最大或最小元素。在存储的时候,为了方便,我们可以将整个二叉堆存到一个数组里,以1为根结点,某一元素两个儿子的下标分别为(2i)和(2i+1),父亲下标为(i/2)。 用途 二叉堆可用于维护一个序列的极值。它支持插入一个元素,删除极值元素和查询极值元素。通过拼接两个二叉堆,我们还可以对删除指定元素的操作。 操作实现 插入 首先将元素插入二叉堆的最后,接着不断与它的父结点比较,若不满足堆的顺序则交换它与它的父结点,直到整个二叉堆重新满足二叉堆的性质(即到达堆顶或当前比较结果满足堆的顺序)。 void insert(const Type &x) { a[++size]=x; unsigned int now=size; while(now>1&&!compare(a[now>>1],a[now])) { swap(a[now>>1],a[now]); now>>=1; } return; } 查询堆顶元素 直接返回根节点即可。 inline Type top(){return

二叉堆

杀马特。学长 韩版系。学妹 提交于 2020-02-08 04:21:35
存储方式 二叉堆用数组存储,从下标1开始,并且因为二叉堆为完全二叉树,所以除根节点外的任意节点 i 的父节点为 i / 2,除终端节点外任意节点 i 的 左孩子为 i * 2,右孩子为 i * 2 + 1(存在右孩子时) 性质 1 是一种特殊的完全二叉树。 2 根节点为优先度最大的数据,根节点的子节点优先度稍微低于根节点,以此类推,越往下优先度越低。优先度不一定为数学意义上的大小,根据实际情况选择。 3 基础的有两种堆,/根节点值最大的堆称为大根堆,反过来,根节点最小的称为小根堆。 插入 void charu ( int x ) { int f ; if ( x <= 1 ) return ; while ( x > 1 ) { f = x / 2 ; if ( s [ x ] < s [ f ] ) swap ( s [ x ] , s [ f ] ) ; else break ; x = f ; } return ; } 删除 删除方式为直接将该结点后面所有结点的前移将其覆盖 int shanchu ( int adress , int end ) { int i ; for ( i = adress ; i <= end - 1 ; i ++ ) s [ i ] = s [ i + 1 ] ; end -- ; return s [ adress ] ; } 例题

二叉堆-19王祥力

牧云@^-^@ 提交于 2020-02-07 01:42:36
二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树))。二叉堆有两种:最大堆和最小堆。最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。 二叉堆的作用就是:增加存储效率。 二叉堆一般用数组来表示。例如,根节点在数组中的位置是0,第n个位置的子节点分别在2n+1和 2n+2。因此,第0个位置的子节点在1和2,1的子节点在3和4。以此类推。这种存储方式便於寻找父节点和子节点。 最大堆的性质是:每个节点都大于等于它的两个子节点。类似的,最小堆的性质是:每个节点都小于等于它的子节点。 两种堆核心思路都是一样的. 对于一个最大堆,根据其性质,显然堆顶,也就是 arr[1] 一定是所有元素中最大的元素。 当其子节点比其大是它就没有资格去做父节点了,这时它应该下台,让比它大的来做父节点。 如图: 让我一段代码来实现: int x; scanf("%d",&x); a[n]=x; int now=n; while(now) { int s=(now-1)/2; if(a[s]<a[now]) { int t=a[s]; a[s]=a[now]; a[now]=t; } else break; now=s; } 上面提到的是添加元素的一种方法,此外还有删除,修改元素。 删除元素 删除元素的过程类似,只不过添加元素是"向上冒",而删除元素是

二叉堆

痴心易碎 提交于 2020-02-07 01:36:04
二叉堆 二叉堆是一种基础数据结构,二叉堆的操作内容包括插入,删除,查询等。 性质: 堆是一颗完全二叉树,堆的顶端一定是“最大”,最小”的,但是要注意一个点,这里的大和小并不是传统意义下的大和小,它是相对于优先级而言的。 堆有两种模式,小根堆和大根堆,分别对应第二个性质中的“堆顶最大”“堆顶最小”,对于大根堆而言,任何一个非根节点,它的优先级都小于堆顶,对于小根堆而言,任何一个非根节点,它的优先级都大于堆顶。 然而二叉堆的代码实现也有两种,包括手写堆和STL; 首先我们通过手写堆来实现对堆的理解。 1.插入 void swap ( int & x , int & y ) { int t = x ; //交换函数 x = y ; y = t ; } int heap [ N ] ; //定义一个数组来存堆 int siz ; //堆的大小 void push ( int x ) //要插入的数 { heap [ ++ siz ] = x ; now = siz ; //插入到堆底 while ( now ) //还没到根节点,还能交换 { ll nxt = now >> 1 ; //找到它的父亲 if ( heap [ nxt ] > heap [ now ] ) swap ( heap [ nxt ] , heap [ now ] ) ; //父亲比它大,那就交换 else

二叉堆相关整理(大根堆小根堆)

别来无恙 提交于 2020-02-04 12:44:36
二叉堆的概念 二叉堆是一种支持 插入、删除、查询最值 的数组结构。它其实是一棵 满足堆性质的完全二叉树 ,树上的每一个节点都带有一个 权值 。 二叉堆的存储 层次序列存储方式 ,直接用一个数组来保存二叉堆。 逐层从左到右为树中的节点依次编号,把此编号作为节点在数组中存储的位置(下标)。在这种存储方式中,父节点编号等于子节点等于子节点编号除以2,左子节点编号等于父节点编号乘2,右子节点编号等于父节点编号乘2加1。 大根堆的几种常见操作 当然小根堆也一样 1.Insert Insert(val)操作向堆中插入一个带有权值val的新节点。我们把这个新节点直接放在存储二叉堆的数组末尾,然后通过交换的方式向上调整,直至满足堆性质。其时间复杂度为堆的深度,即 O(logn) 。 const int SIZE = 1e5 + 7 ; int heap [ SIZE ] , n ; void up ( int p ) { while ( p > 1 ) { if ( heap [ p ] > heap [ p / 2 ] ) { swap ( heap [ p ] , heap [ p / 2 ] ) ; //向上交换 p / = 2 ; } else { break ; } } } void insert ( int val ) { heap [ ++ n ] = val ; up ( n )