最小堆

数据结构-队列小结

眉间皱痕 提交于 2020-01-31 09:28:14
数据结构之队列 对比学习法:通过对比A和B的不同和差异来学习A和B 前置知识 数组和链表的知识 1. 先进先出队列(FIFO QUEUE) 1.1 理论知识 只允许头出,尾进。像排队一样。 如果是先进后出.则是栈。 对数组和链表可以随机存取,对队列只能尾存头取,是随机存取的一个操作子集。所以,队列其实是数组和链表就可以实现 1.2 实现 基于数组实现: 数组头部移出,尾部插入,只需要一个数组和头尾两个指针即可实现。 效率: 头取效率 O(1) 尾存效率 O(1) 缺点: 假溢出: 数组长度有限,尾部不断添加,导致头部有大量空白的情况下,数组越界。 因此: 引入循环队列的概念。 基于链表实现: 链表本身就是队列的父集合,单向链表+头尾指针就可以实现队列,所以java中没有链表队列实现,直接链表就可以起到相同作用 效率: 头取效率 O(1) 尾存效率 O(1) 小结: 单向链表可以替代队列实现 数组实现有假溢出的问题。 2.循环队列 因为链表不存在容量问题,所以循环链表只针对数组实现 数组实现的先进先出链表存在假溢出问题,为了解决假溢出问题,提出循环链表概念。 1.头指针表示出队位置。 2.尾指针表示入队位置。 3.当尾指针达到数组最后的位置的时候,跳到数组开头的位置,头指针也相同处理。 缺点: 容量有限,和数组容量相同,如果队列同时容纳的人超过了数组长度,则首尾碰撞,出现异常。

Python学习:heapq模块

五迷三道 提交于 2020-01-18 02:12:50
简介 在Python中,heapq模块是实现最小堆的模块。 堆是非线性的树形数据结构,有两种堆,即最大堆与最小堆。 最大堆,指的是树的各个父节点的值,总是大于或者等于任何一个子节点的值。 最小堆,指的是树的各个父节点的值,总是小于或者等于任何一个子节点的值。因此整个最小堆的最小元素总是位于树的根节点。 在Python提供的heapq模块中,堆数据结构最重要的特征是heap[0]永远是最小的元素。 方法 在heapq模块中,模块提供的方法如下: 方法原型 方法解析 heapq.heappush(heap,item) 将元素item推送至堆heap中 heapq.heappop(heap) 从堆中弹出最小元素,如果堆是空,则IndexError,获取最小元素而不弹出元素,可使用heap[0]。函数返回堆中最小元素。 heapq.heappushpop(heap,item) 将元素item推送至堆heap中,然后从堆中弹出最小元素。函数返回最小元素。 heapq.heapify(x) 将列表x转换为堆,即创建堆 heapq.heapreplace(heap,item) 弹出堆中的最小元素,然后将元素item推送至堆中,如果堆是空,则IndexError。函数返回堆中最小元素 heapq.merge(*iterables,key=None,reverse=False)

JAVA并发包(十三):PriorityBlockingQueue

北城余情 提交于 2020-01-17 01:43:57
PriorityBlockingQueue中文名可以叫做优先阻塞队列,它的内部是数组结构的最小堆,能够保证每次取出的都是队列中最小的节点(比较器返回的最小元素)。但是它在数组中不是有序的b,只保证数组的第一个节点是最小的,也就是说第一个优先权最高,首先会被取出。 下图就是一个最小堆的示意图,它可以说是一个二叉树的结构,只需要保证父节点大于子节点,就满足最小堆的要求。然后就是从父节点开始,从上往下,从左往右把节点放到数组里。 参考: 图解最小堆形成-以数组方式表示 一、内部代码结构 /** 初始队列容量 */ 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

greedy策略求解Huffman编码

谁说我不能喝 提交于 2020-01-13 21:29:11
Huffman编码的原理为:每次选择数据集datas中当前第1小和第2小的2个数来构建左右子树,而这2个子树的父节点则是这2个子树的和,然后将该和放入父节点的datas中,再在新的数据集中选择两个子树继续构建,直到数据集中只剩下一个数据为止。总共构建次数为n-1次。 而Huffman的greedy策略点为每 次选择数据值倒数2个进行构建, 因为Huffman的原则是频率越大的数越最先编码,即频率越大的数越靠近树根,这样的话,需要的编码字符越少,那么我们应该如何选择构建Huffman树呢?根据数据越大越靠近树根,数据越小则越靠近底层,本文可以将数据越小的先构建树,然后再大一点的数A与先构建的树根一起再构建树,这样再大一点的这个数A一定比前面两个最小的数就越靠近树根,那么在再大一点的数A到root的路径(length)就更短一点,每个叶子节点到root的路径长度就是coding长度。 所以greedy策略点最终还是回归到问题本身,即回归到了问题的求解目的(如何给字符编码使得总的code最短)。 那么如何实现该算法呢? (1)其实按照直接每次提取最后的2个数进行构建,则每次提取前进行一下排序就行,这个可通过合并排序解决,但是前面已排过一次,基本有序,每次对基本有序的数据在排序,也比较耗时,而每次得到最小的数,存在一个更好的数据结构:最小堆,即优先队列。只要我们连续取2次即可

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++语言描述》中最小堆的建立插入删除的图解,再给出本人的实现代码,最好是先看明白图后再去看代码。 堆的插入 每次插入都是将新数据放在数组最后。可以发现从这个新数据的父结点到根结点必然为一个有序的数列,现在的任务是将这个新数据插入到这个有序数据中——这就类似于 直接插入排序 中将一个数据并入到有序区间中,对照 《白话经典算法系列之二 直接插入排序的三种实现》

算法导论学习之——堆排序

血红的双手。 提交于 2019-12-31 02:36:34
在这一篇文章中,首先介绍一下堆的属性和性质。然后讲解一下建堆的过程,最后讲解堆排序。 1、堆的介绍 堆的物理存储结构就是一个一维的数组,其数据结构就是一个完全的二叉树。需要注意的是堆中的每个结点不需要后继指针,其父节点和左右孩子结点都可以通过计算得到。假设要计算结点i(i为数组的下标)的父节点和左右孩子结点,可以使用以下公式计算: 在此计算的都是结点的数组下标, 由于堆的数据结构是一个完全二叉树,设该完全二叉树有n个结点。则其内部结点下标分别为:1,2,。。。 故其叶子结点下标分别为: 堆高度:就是从根节点到最长叶子结点的距离。包含N个结点的堆高为: 其次是最大堆和最小堆问题,最大堆就是对任意的父节点的值总是大于或等于孩子节点的值,这样的话就能保证根节点保存堆中的最大元素。 即:A[parent(i)] >=A[i] (最大堆) 同样,最小堆就是对任意的父节点的值小于或等于孩子结点的值,这样就能保证根节点的值最小。 即:A[parent(i)] <=A[i] (最小堆) 一般情况下,最大堆用于堆排序中,最小堆用于优先队列中。 2、建堆 根据堆的性质,我们最终要得到堆的根节点是一个最值,因而,我们需要自底向上进行建堆,若自顶向下建堆的话则不能保证根节点是最值。在此仅讨论建立最大堆的情况。 首先我们可以认为每个叶子结点已经是一个最大堆,然后从最末一个非叶子结点 开始进行对调整

堆排序(摘自算法导论)

筅森魡賤 提交于 2019-12-31 02:35:58
(二叉)堆是一个数组,他可以被看成一个近似的完全二叉树。树上的每一个节点对应数组中的一个元素,除了最底层之外,该树是完全填满的,而且是从左向右填充。表示堆的数组A包括两个属性,A.length给出数组元素的个数,A.heap-size表示有多少个堆元素存储在该数组中。也就是说,虽然A[1..A.length]可能都有数据,但只有A[1..A.heap-size]中存放的是堆的有效元素。0<=A.heap-size<=A.length。树的根节点是A[1],这样给定一个节点的下标i,我们很容易计算得到它的父节点、左孩子和右孩子的下标。 PARENT(i) return[i/2] LEFT(i) return 2i RIGHT(i) return 2i+1 二叉堆可以分为两种形式:最大堆和最小堆。 在最大堆中,最大堆是指除了根节点之外的所有节点i都要满足 A[PARENT(i)]>=A[i] 也就是说,某个节点的最大值至多与根节点一样大。因此,堆中最大的元素存在根节点中;并且,在任一子树中,该子树所包含的所有节点的值都不大于该子树根节点的值。最小堆的组织方式正好相反 最小堆性质市值除了根节点之外的所有节点i都有 A[PARENT[i]]<=A[i] 在堆排序算法中,我们使用的是最大堆,最小堆通常用于构造优先队列。 如果把堆看成一棵树

Top K问题的两种解决思路

眉间皱痕 提交于 2019-12-23 17:57:07
海量数据中找出前k大数(topk问题) 前两天面试3面学长问我的这个问题(想说TEG的3个面试学长都是好和蔼,希望能完成最后一面,各方面原因造成我无比想去鹅场的心已经按捺不住了),这个问题还是建立最小堆比较好一些。 先拿10000个数建堆,然后一次添加剩余元素,如果大于堆顶的数(10000中最小的),将这个数替换堆顶,并调整结构使之仍然是一个最小堆,这样,遍历完后,堆中的10000个数就是所需的最大的10000个。建堆时间复杂度是O(mlogm),算法的时间复杂度为O(nmlogm)(n为10亿,m为10000)。 优化的方法:可以把所有10亿个数据分组存放,比如分别放在1000个文件中。这样处理就可以分别在每个文件的10^6个数据中找出最大的10000个数,合并到一起在再找出最终的结果。 以上就是面试时简单提到的内容,下面整理一下这方面的问题: top K问题 在大规模数据处理中,经常会遇到的一类问题:在海量数据中找出出现频率最好的前k个数,或者从海量数据中找出最大的前k个数,这类问题通常被称为top K问题。例如,在搜索引擎中,统计搜索最热门的10个查询词;在歌曲库中统计下载最高的前10首歌等。 针对top K类问题,通常比较好的方案是分治+Trie树/hash+小顶堆(就是上面提到的最小堆),即先将数据集按照Hash方法分解成多个小数据集

哈夫曼树(一)之 C语言详解

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-19 12:40:19
哈夫曼树(一)之 C语言详解 本章介绍哈夫曼树。和以往一样,本文会先对哈夫曼树的理论知识进行简单介绍,然后给出C语言的实现。后续再分别给出C++和Java版本的实现;实现的语言虽不同,但是原理如出一辙,选择其中之一进行了解即可。若文章有错误或不足的地方,请帮忙指出! 目录 1 . 哈夫曼树的介绍 2 . 哈夫曼树的图文解析 3 . 哈夫曼树的基本操作 4 . 哈夫曼树的完整源码 转载请注明出处: http://www.cnblogs.com/skywang12345/ 更多内容: 数据结构与算法系列 目录 哈夫曼树的介绍 Huffman Tree,中文名是哈夫曼树或霍夫曼树,它是最优二叉树。 定义 :给定n个权值作为n个叶子结点,构造一棵二叉树,若树的带权路径长度达到最小,则这棵树被称为哈夫曼树。 这个定义里面涉及到了几个陌生的概念,下面就是一颗哈夫曼树,我们来看图解答。 (01) 路径和路径长度 定义 :在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。 例子 :100和80的路径长度是1,50和30的路径长度是2,20和10的路径长度是3。 (02) 结点的权及带权路径长度 定义 :若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权