二叉堆

《数据结构》学习笔记 第10章 优先级队列

倖福魔咒の 提交于 2020-02-04 10:42:31
1, 需求:根据优先级而不是数据进来的次序进行处理。 2, 优先级队列接口: 3,几种可能的实现: 基于向量/有序向量:部分接口效率有待改进。 基于列表/有序列表:部分接口效率有待改进。 基于BBST:三个接口均可O(logN)复杂度。 但BBST过于强大了,需要查找极值元;不需要维护全序关系,只需偏序即可。 4, 完全二叉堆:借助于完全二叉树,实现优先级队列。 完全二叉树: 完全二叉堆,及其实现: 堆序性:完全二叉堆的灵魂。 堆序性定义:任何一个节点,在数值上,都不会超过他的父亲。 最大元:在根节点处 (内部数组首元素)。 5,完全二叉堆的插入与上滤 效率:渐进意义上 O(logN). 常数意义上,存在改进的空间。 6,完全二叉堆的删除与下滤 效率:渐进意义上 O(logN). Note:每次下滤,做两次比较。 7, 完全二叉堆的批量建堆 自上而下的上滤:O(n), 效率不高。 自下而上的下滤:O(logn) 来源: https://www.cnblogs.com/sanlangHit/p/12258461.html

算法-11-堆排序

心已入冬 提交于 2020-01-29 07:16:56
目录 1、二叉堆 2、堆排序 3、代码 4、应用场景 1、二叉堆 二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。二叉堆有两种: 最大堆 和 最小堆 。最大堆: 父结点 的键值总是大于或等于任何一个子 节点 的键值 ;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。 二叉堆一般用 数组 来表示 。如果根节点在数组中的位置是1,第 n 个位置的子节点分别在2 n 和 2 n +1。因此,第1个位置的子节点在2和3,第2个位置的子节点在4和5。以此类推。这种基于1的数组存储方式便于寻找父节点和子节点。 下图中a[1]的子结点就是a[2]和a[3]. 2、堆排序 堆排序就是利用了二叉堆中的 最大堆 。即每个父结点(数组中下标k),都要大于等于它的子结点(数组中下标2k和2k+1)。 堆排序的步骤:1、对于一个无序数组a,先将它构建成 最大堆。 这时候二叉堆的 根节点 就是数组中 最大的那个元素 。 2、然后我们把最大的根节点拿出来放在该数组中末尾。 3、将剩下的元素再构建成 最大堆 ,得到第二大元素,放在第一大元素的前面。 4、不断循环。。。。。。。。。。。。。。。。类似冒泡排序的思想,每次先把最大的元素拿出来放在末尾。 3、代码 public class Heap { public static void sort(double[] a){ /

算法-10-优先队列

久未见 提交于 2020-01-26 17:29:00
目录 1、背景 2、优先队列 3、二叉堆 4、插入函数-insert() 5、删除最大元素- delMax() 6、完整代码 7、三叉树 1、背景 考虑以下问题:输入 N 个int值,从中找出最大的(或是最小的)M 个int值。这中情景可以出现在:比如每个月的账单有很多记录,我只需要消费最大的5笔记录。那么我们的实现方法是什么呢? 方法一:将这N个int值排序,然后依次输出最大的M个。(如果数据量庞大,你得每次等到排序完之后才能拿到你想要的值,无法立即得到) 方法二:每次有新的消费记录插入的时候,都和那M(5)笔最大的记录进行比较。(除非M很小,否则代价很大) 方法三:优先队列(插入的时候就最大元素已经放在了合适的位置,等待获取) 2、优先队列 优先队列是一种抽象数据类型,和栈和队列类似,只是职能不一样。 它的主要职能是:1、删除(获取)最大的元素; 2、插入元素 插入和删除元素实现方式有三种: 第一种是插入的时候就排序好,这样取的时候直接拿就好了。(有序数组) 第二种是插入的时候不管,取的时候遍历拿到最大的元素。(无序数组) 第三种就是二叉 堆。 下面是这三种的时间复杂度。 3、二叉堆 二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。二叉堆有两种: 最大堆 和 最小堆 。最大堆: 父结点 的键值总是大于或等于任何一个子 节点 的键值;最小堆

常见基本的数据结构——优先队列(堆)

有些话、适合烂在心里 提交于 2020-01-19 22:19:01
在多用户环境中,操作系统调度程序必须决定在若干进程中运行那个进程。一般一个进程只能被允许运用一个固定的时间片。一种算法是使用一个队列。开始时作业被放在队列的末尾。调度程度将反复提取队列中的第一个作业并运行它,直到运行完毕或者该作业的时间片被用完,并在作业为被用完时将其放入队列的末尾。但是一般来说,短的作业要尽可能快地结束,这一点很重要,因此在已经被运行的作业中这些短作业应该拥有优先权。此外,有些作业虽然短小但也很重要,也应该拥有优先权。这种特殊的应用似乎需要一些特殊的队列,我们称之为优先队列。 模型 优先队列应该允许至少下面的两种操作,Insert(插入),以及DeleteMin(删除最小值),它的作用是找出,返回和删除优先队列中的最小值。Insert操作相当于队列的入队,DeleteMin操作相当于队列中的出队操作。在贪婪算法中,优先队列也是重要的,因为该算法通过反复的求出最小元来进行计算。 一些简单的实现 使用简单链表可以在表头进行插入并以O(1)的时间复杂度,但是遍历最小元的话则需要O(N)的时间复杂度。另外的一种思路是始终保持排序状态,这使得插入的高昂代价O(N),而DeleteMin的代价是O(1),但是在实际中,DeleteMin的操作次数从不多于插入的操作次数。 还可以使用二叉查找树来实现优先队列,它对这两种操作的时间都是O(logN)

一步步地分析排序——优先队列和堆排序

断了今生、忘了曾经 提交于 2020-01-15 03:55:00
本文框架 定义和使用场景 优先队列是一个抽象数据类型,和栈、队列类似,它们都是抽象数据类型,相当于一个Java类,有自己的属性,并对外提供API。在了解它有什么API之前,先来看看优先队列的使用场景。 优先队列适用于需要对集合不断地执行插入元素、删除最大(或最小)元素的场景。这个场景大体可以分为两类: 第一类是业务实际情况需要,比如CPU的任务调度,待执行的任务是一个集合,每启动一个新程序就是在向集合里面插入元素。当前程序执行完后,就要从集合里面取出下一个优先级最高的程序。不断地有程序被启动和被执行,就像不断地对集合执行插入、删除最大元素的操作。 第二类场景是“从N个元素里获取最大的M个元素,N很大,不能一次性全部读进内存”,比如从银行成百上千万条交易记录里面找到金额最大的10笔交易;或者从全国的手机号码里面找到使用年限最长的10个号码。对于第二类场景,问题本身并不需要不断地对集合进行插入、删除操作。如果内存没有限制的话,你可以一次性将数据全部装进集合,然后随便选择一个排序算法对集合进行降序排列,接着输出最前面的10个元素。但是由于待处理的数据量过大(相对内存而言),不能使用排序算法解决该类问题,以银行交易记录为例子,你可以用优先队列通过如下步骤解决: 创建一个容量为11的集合 向集合里插入一笔交易记录,如果插入后集合的元素达到11个,删除金额最小的一笔交易( 需要注意的是

优先级队列与堆排序

偶尔善良 提交于 2020-01-11 04:12:32
转自:http://www.cnblogs.com/yangecnu/p/Introduce-Priority-Queue-And-Heap-Sort.html 在很多应用中,我们通常需要按照优先级情况对待处理对象进行处理,比如首先处理优先级最高的对象,然后处理次高的对象。最简单的一个例子就是,在手机上玩游戏的时候,如果有来电,那么系统应该优先处理打进来的电话。 在这种情况下,我们的数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue) 。 本文首先介绍优先级队列的定义,有序和无序数组以及堆数据结构实现优先级队列,最后介绍了基于优先级队列的堆排序(Heap Sort) 一 定义 优先级队列和通常的栈和队列一样,只不过里面的每一个元素都有一个”优先级”,在处理的时候,首先处理优先级最高的。如果两个元素具有相同的优先级,则按照他们插入到队列中的先后顺序处理。 优先级队列可以通过链表,数组,堆或者其他数据结构实现。 二 实现 数组 最简单的优先级队列可以通过有序或者无序数组来实现,当要获取最大值的时候,对数组进行查找返回即可。代码实现起来也比较简单,这里就不列出来了。 如上图: · 如果使用无序数组,那么每一次插入的时候,直接在数组末尾插入即可,时间复杂度为O(1),但是如果要获取最大值

Python 堆与堆排序

我是研究僧i 提交于 2020-01-10 07:02:09
堆排序 与 快速排序 , 归并排序 一样都是时间复杂度为O(N*logN)的几种常见排序方法。学习堆排序前,先讲解下什么是数据结构中的二叉堆。 二叉堆的定义 二叉堆是完全二叉树或者是近似完全二叉树。 二叉堆满足二个特性: 1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。 2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。 当父结点的键值总是大于或等于任何一个子节点的键值时为 最大堆 。当父结点的键值总是小于或等于任何一个子节点的键值时为 最小堆 。下图展示一个最小堆: 由于其它几种堆(二项式堆,斐波纳契堆等)用的较少,一般将二叉堆就简称为堆。 堆的存储 一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。 堆的操作——插入删除 下面先给出《 数据结构 C++语言描述》中最小堆的建立插入删除的图解,再给出本人的实现代码,最好是先看明白图后再去看代码。 堆的插入 每次插入都是将新数据放在数组最后。可以发现从这个新数据的父结点到根结点必然为一个有序的数列,现在的任务是将这个新数据插入到这个有序数据中——这就类似于 直接插入排序 中将一个数据并入到有序区间中,对照 《白话经典算法系列之二 直接插入排序的三种实现》

堆和堆排序

大憨熊 提交于 2020-01-10 07:01:26
堆排序 与 快速排序 , 归并排序 一样都是时间复杂度为O(N*logN)的几种常见排序方法。学习堆排序前,先讲解下什么是数据结构中的二叉堆。 二叉堆的定义 二叉堆是完全二叉树或者是近似完全二叉树。 二叉堆满足二个特性: 1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。 2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。 当父结点的键值总是大于或等于任何一个子节点的键值时为 最大堆 。当父结点的键值总是小于或等于任何一个子节点的键值时为 最小堆 。下图展示一个最小堆: 由于其它几种堆(二项式堆,斐波纳契堆等)用的较少,一般将二叉堆就简称为堆。 堆的存储 一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。 堆的操作——插入删除 下面先给出《数据结构C++语言描述》中最小堆的建立插入删除的图解,再给出本人的实现代码,最好是先看明白图后再去看代码。 堆的插入 每次插入都是将新数据放在数组最后。可以发现从这个新数据的父结点到根结点必然为一个有序的数列,现在的任务是将这个新数据插入到这个有序数据中——这就类似于 直接插入排序 中将一个数据并入到有序区间中,对照 《白话经典算法系列之二 直接插入排序的三种实现》

heapsort--堆排序简单实现

∥☆過路亽.° 提交于 2019-12-28 04:03:46
1,什么是二叉堆? 1),父节点总是大于等于(或者小于等于)子节点。 2),每个节点及其部分都是一个二叉堆。 3),他是一个完全二叉树。 2,堆排序。 1),调整堆,首先排序序列是一个物理上的顺序存储表,逻辑上的完全二叉树。调整为二叉堆的方式就是从最后一个非叶子节点(N/2-1)开始调整为满足二叉堆的性质。 2),堆排序。就是记录第一节点根节点的值,把最后一个替换第一值,重新调整新的堆步骤1),直到剩下最后一个元素。时间复杂度为O(N*logN)。 3),python简单实现。(python2.7) #!/usr/bin/env python# -*- coding:utf-8 -*- #the max heapdef MaxHeapAdjust(dist): length=len(dist) halflen=length/2-1 for index in range(halflen,-1,-1): leftindex=2*index rightindex=2*index+1 if leftindex>=length: break if dist[index]<dist[leftindex]: templ=dist[index] dist[index]=dist[leftindex] dist[leftindex]=templ #MaxHeapAdjust(dist) if

堆排序

僤鯓⒐⒋嵵緔 提交于 2019-12-28 04:00:47
http://www.cnblogs.com/skywang12345/p/3602162.html 堆是一种数据结构,其约束(根节点大于左右子节点——大根堆,根节点小于左右子节点——小根堆),一般用完全二叉树表示,用数组直接存储 堆排序包括两部分:1,构造堆,保证堆的性质 2,输出根节点,并调整堆(将根节点与叶子节点调换,堆的性质被打破)使得余下的节点使其仍然构成堆 堆的插入删除 堆的插入:每次插入都是将新数据放在数组最后。可以发现从这个新数据的父结点到根结点必然为一个有序的数列,现在的任务是将这个新数据插入到这个有序数据中——这就类似于 直接插入排序 中将一个数据并入到有序区间中 // 新加入i结点 其父结点为(i - 1) / 2 void MinHeapFixup(int a[], int i) { int j, temp; temp = a[i]; j = (i - 1) / 2; //父结点 while (j >= 0 && i != 0) { if (a[j] <= temp) break; a[i] = a[j]; //把较大的子结点往下移动,替换它的子结点 i = j; j = (i - 1) / 2; } a[i] = temp; } void MinHeapFixup(int a[], int i) { for (int j = (i - 1) / 2; (j