精华内容
下载资源
问答
  • 最小堆以及最小优先队列实现什么是最小堆构建最小堆MIN_HEAPITY的实现MAX_HEAPIFY的时间复杂度分析BUILD_MIN_HEAP的实现建最小堆的时间复杂度分析 什么是最小堆 最小堆从逻辑上可以理解为一个完全二叉树(如图a所...

    什么是最小堆

    最小堆从逻辑上可以理解为一个完全二叉树(如图a所示),最小堆的性质很简单,即除了根节点以外,所有的节点都要小于其左右子节点,而从物理存储上看,它是由数组的形式来存储的(如图b所示)。
    最小堆可以应用于最小优先队列的构建以及堆排序算法的实现,后面我会继续更新最小优先队列的实现。
    注意:数组下标是从1开始的。
    在这里插入图片描述

    要如何通过数组来体现二叉树的性质呢?我们通过观察可以发现运用数组的下标运算可以很容易找到父子节点之间的联系:

    节点A[i]的父节点下标为i/2(取下界)
    节点A[i]的左子节点下标为2i
    节点A[i]的右子节点下标为2
    i+1

    通过这样的联系我们就可以通过数组来构建二叉树,并利用二叉树的性质来构建最小堆。

    构建最小堆

    要实现最小堆,我们的思路是:自底向上,逐步调整二叉堆。即每次选中一个A[i]节点,然后将以A[i]节点作为根结点的最大子树调整为最小堆。因此我们需要实现以下两个函数:

    MIN_HEAPIFY(A,i) #用于维护最小堆的性质
    BUILD-MIN-HEAP(A)#用于建堆

    MIN_HEAPITY的实现

    MIN_HEAPITY的输入是数组A和下标i,其具体功能是将以A[i]作为根结点的子树调整为最小堆,其实现方法是利用递归。
    递归过程:先从A[i]的左右子节点中选出最小的,记住其下标j,再将A[i]与A[j]交换数值。然后再次调用MIN_HEAPITY函数,以A数组和下标j作为输入,继续将以A[j]为根结点的最大子树调整为最小堆。
    代码如下:

    void MIN_HEAPITY(node A[n],int i){//维护堆的性质
        int l=2*i;//左子节点
        int r=2*i+1;//右子节点
        int min=0;//记录最小值下标
        if(l<=heap_size&&A[l].value<A[i].value){//若左子节点的值小于当前节点,则更新最小值下标
            min=l;
        }
        else min=i;
        if(r<=heap_size&&A[r].value<A[min].value)min=r;//若右子节点的值小于当前节点,则更新最小值下标
        if(min!=i){//判断是否需要继续更新
            int temp=A[i].value;
            A[i].value=A[min].value;
            A[min].value=temp;
            temp=A[i].key;
            A[i].key=A[min].key;
            A[min].key=temp;
            MIN_HEAPITY(A,min);
        }
    }
    

    MIN_HEAPIFY的时间复杂度分析

    假设二叉树的节点总数为n,所以其每个孩子节点的子树大小最多为2n/3(提示:此时最底层一定是半满的状态,可利用满二叉树叶节点数量-非叶节点数量=1 来证明)。故可利用下面这个递归式来计算运行时间:

    T(n)≦T(2n/3)+O(1)

    根据主定理求解可以得到上述递归式的解为T(n)=O(lg n),即MIN_HEAPIFY的时间复杂度为O(lg n)。

    BUILD_MIN_HEAP的实现

    每一个叶节点都可以看作是只有一个元素的最小堆,所以我们不用从叶节点开始建堆。根据完全二叉树的性质我们知道,叶节点的数量为n/2(取下界),所以我们只需要从A[n/2]开始向A[1]不断建堆即可。
    代码如下:

    void BUILD_MIN_HEAP(node A[n]){//建堆
        for(int i=heap_size/2;i>=1;i--){//从非叶节点逐步调整
            MIN_HEAPITY(A,i);
        }
    }
    

    建最小堆的时间复杂度分析

    因为每次调用MIN_HEAPIFY的时间复杂度是O(lg n),而BUILD_MIN_HEAP需要O(n)次这样的调用,故总的时间复杂度为O(nlg n)

    展开全文
  • 概观的的PriorityQueue类一部分的java.util包,一个通用的实现Java中的基于优先级的队列。甲队列基本上一个数据结构,用于定义特定规范来插入和从存放物品的检索的处理。这个想法非常类似于许多人站在队列中说...

    该PriorityQueue中是很重要的一个Java的建立在无界优先级队列和优先级堆的API。本文通过适当的代码示例介绍了有关此API及其使用的一些复杂信息。

    概观

    的的PriorityQueue类是一部分的java.util包,是一个通用的实现Java中的基于优先级的队列。甲队列基本上是一个数据结构,用于定义特定规范来插入和从存放物品的检索的处理。这个想法非常类似于许多人站在队列中说,获得一张票。站在队列中的第一个人获得了获得机票的第一个机会,最后一个人获得了一个机会。人们被添加到队列的末尾或尾端。向队列添加项目在技术上称为入队过程,从队列中删除的项目来自行中的第一个项目。这被称为出队。我们的想法是以FIFO(先进先出)的方式对元素进行排序。

    现在,这是最简单的架构,并且紧密地定义了队列实际意味着什么以及如何在计算机中进行模拟。甲商店通常由一个简单的阵列,其中所述存储和检索过程有这样的定义范数表示。优先级队列强加了一些特殊规范。我们将看到更多的内容。

    Java实现队列

    Java API 在java.util包中具有通用接口名称Queue 。这是Java Collection Framework API的一部分,旨在在处理之前保存元素。作为Collection的一部分,它具有所有基本的Collection操作。特定于其身份的操作涉及插入,提取和检查存储在其中的元素。这些操作中的每一个都有两种不同的形式,例如,如果操作失败则抛出异常,另一种返回特殊值,例如null或false,具体取决于操作。注意与典型队列不同,Java Queue的具体实现不一定以FIFO方式排序元素。对于基于优先级的队列尤其如此,其中元素的排序是根据提供的比较器或自然顺序完成的。但无论顺序如何,remove()或poll()方法将始终检索队列头部的元素。这两种不太可能的方法之间的具体区别似乎是一个类似的方法是一个抛出异常(NoSuchElementException)失败,而后者返回(null),一个特殊的值。

    76837767a007e4391ec793f5ed552246.png
    35cc0e9e82952ac8251ad763cf789fbf.png

    请注意,Queue 接口不适合在并发编程中使用,因为它没有定义阻塞队列方法,其中enqueue和dequeue进程等待元素出现在队列中或大小可用。有一个名为BlockingQueue 的特定接口,它扩展了Queue 接口并解决了这些问题。

    有一个名为AbstractQueue 的抽象类,它提供了一些队列操作的部分实现。所述的PriorityQueue 类是这个抽象类的直接延伸。

    优先级队列

    优先级队列的Java实现是一种特殊类型的队列,其中元素的排序由其自然排序原则确定或根据创建期间提供的比较器定制。我们在构造期间调用的构造函数决定了与优先级队列一起使用的排序原则。与Queue 不同,它不允许null元素,但是某些实现 - 例如LinkedList -do也不禁止插入null元素。但是,PriorityQueue 根本不允许使用null元素。如果优先级队列是根据自然顺序构造的,则会抛出任何不可比较的元素插入ClassCastException

    它被声明是无限的并且基于优先级堆。虽然队列的大小被称为无界,但是有一个内部容量来确定数组的大小。插入元素时,此大小会自动增大。但是,没有具体说明尺寸增加的原则的细节。

    有七种类型的重载构造函数,我们可以通过它们设置参数来指定队列的初始容量,为Comparator提供指定元素的自定义排序,或者使用无参数构造函数接受默认值。

    • PriorityQueue中()
    • PriorityQueue(int initialCapacity)
    • PriorityQueue(int initialCapacity,Comparator comparator)
    • PriorityQueue(Commection c)
    • PriorityQueue(比较器比较器)
    • PriorityQueue(PriorityQueue c)
    • PriorityQueue(SortedSet c)

    Queue 类似,PriorityQueue 也不同步,因此应在并发编程中谨慎使用。但是,有一个同步替代它,称为PriorityBlockingQueue 。这与PriorityQueue 的工作方式相同,只是具有线程安全的附加资格。

    PriorityQueue 中定义的操作与Queue 相同,但增加了一些。

    64858640956c933ffeb3333be072cf67.png

    快速示例#1

    让我们用一个简单的程序实现PriorityQueue 的一些操作。

    package org.mano.examples;import java.util.Arrays;import java.util.Iterator;import java.util.PriorityQueue;public class Example1 { public static void main(String[] args){ PriorityQueue pq = new PriorityQueue<>(); pq.add("Mercury"); pq.add("Venus"); pq.add("Earth"); pq.add("Mars"); pq.add("Jupiter"); pq.add("Saturn"); // Get the most priority element based upon // natural alphabetic ordering in string System.out.println("Priority element "+pq.peek()); // Queue elements show(pq); // Remove top of the queue element pq.poll(); show(pq); // Retrieves element from the head of the queue pq.remove("Earth"); show(pq); String result = pq.contains("Earth")? "Found Earth":"Earth Missing!"; System.out.println(result); Object[] arr = pq.toArray(); Arrays.sort(arr); System.out.println(""); for (int i = 0; i pq){ Iterator itr = pq.iterator(); while (itr.hasNext()) System.out.print(itr.next()+"::"); System.out.println(""); }}

    产量

    Priority element EarthEarth::Jupiter::Mercury::Venus::Mars::Saturn::Jupiter::Mars::Mercury::Venus::Saturn::Jupiter::Mars::Mercury::Venus::Saturn::Earth Missing!Jupiter::Mars::Mercury::Saturn::Venus::

    快速示例#2

    这是另一个自定义比较器的快速示例。

    package org.mano.examples;import java.util.Comparator;import java.util.PriorityQueue;public class Planet implements Comparable{ private String name; private double orbitPeriodInDays; public Planet(String name, double orbitPeriodInDays) { this.name = name; this.orbitPeriodInDays = orbitPeriodInDays; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getOrbitPeriodInDays() { return orbitPeriodInDays; } public void setOrbitPeriodInDays(double orbitPeriodInDays) { this.orbitPeriodInDays = orbitPeriodInDays; } @Override public int compareTo(Planet o) { return 0; } @Override public String toString() { return "Planet{" + "name='" + name + ''' + 
    展开全文
  • 优先队列

    2020-12-01 09:28:37
    什么是队列 通过上面的链接,我们可以知道什么是一般的队列,它的特性就是先进先出 但这里的优先队列不再遵循先进先出的原则,而是分为两种情况: 最大优先队列:无论入队...这里用最大堆实现最大优先队列,如下: ...

    什么是队列

    通过上面的链接,我们可以知道什么是一般的队列,它的特性就是先进先出

    但这里的优先队列不再遵循先进先出的原则,而是分为两种情况:

    最大优先队列:无论入队顺序如何,都是当前最大的元素优先出列
    
    最小优化队列:无论入队顺序如何,都是当前最小的元素优先出列
    

    这里用最大堆实现最大优先队列,如下:

    package main
    
    /*
      利用最大堆实现最大优先队列
    */
    
    import "fmt"
    
    type Queen struct {
    	slice  []int
    	length int
    }
    
    // 最大堆尾节点的上浮操作(较大者上浮) O(logn)
    func (m *Queen) upAdjust() {
    	if m.length <= 1 {
    		return //最多一个节点,不用操作
    	}
    	childIndex := m.length - 1          //尾节点索引
    	parentIndex := (childIndex - 1) / 2 //尾节点的父节点索引
    	temp := m.slice[childIndex]
    	for childIndex > 0 && temp > m.slice[parentIndex] {
    		m.slice[childIndex] = m.slice[parentIndex]
    		childIndex = parentIndex
    		parentIndex = (childIndex - 1) / 2
    	}
    	m.slice[childIndex] = temp
    }
    
    // 最大堆节点的下沉操作(较小者下沉) O(logn)
    func (m *Queen) downAdjust(parentIndex int) {
    	temp := m.slice[parentIndex]    //保存父节点的值,用于最后的赋值
    	childIndex := 2*parentIndex + 1 //获取左孩子节点索引
    	for childIndex < m.length {     //存在左孩子
    		if childIndex+1 < m.length && m.slice[childIndex+1] > m.slice[childIndex] { //如果右孩子存在且小于左孩子,取右孩子的值。总之是取到最小孩子节点值
    			childIndex += 1
    		}
    		if temp > m.slice[childIndex] {
    			break //父节点小于最小孩子节点值,结束上浮操作
    		} else {
    			//完成一次下沉操作,再开始下一次
    			m.slice[parentIndex] = m.slice[childIndex]
    			parentIndex = childIndex
    			childIndex = 2*parentIndex + 1
    		}
    	}
    	m.slice[parentIndex] = temp
    }
    
    //获取最大优先队列长度
    func (m *Queen) Length() int {
    	return m.length
    }
    
    //入列操作
    func (m *Queen) enqueue(value int) {
    	m.slice = append(m.slice, value)
    	m.length++
    	m.upAdjust()
    }
    
    // 出列操作
    func (m *Queen) dequeue() int {
    	if m.length == 0 {
    		panic("queen length = 0")
    	}
    	res := m.slice[0]                //出列元素
    	m.slice[0] = m.slice[m.length-1] //将头节点替换成尾节点
    	m.slice = m.slice[:m.length-1]   //删除原来的尾节点,相当于删除了头节点
    	m.length--
    	m.downAdjust(0) //将头节点执行一次下沉操作,使之保持最大堆
    	return res
    }
    
    //构建最大优先队列 O(n)
    func (m *Queen) buildMaxHeap() {
    	for i := (len(m.slice) - 2) / 2; i >= 0; i-- {
    		//从最后一个非叶子节点开始,向上依次执行下沉操作
    		m.downAdjust(i)
    	}
    }
    
    //生成一个空队列
    func NewQueen() Queen {
    	Queen := Queen{
    		slice:  []int{},
    		length: 0,
    	}
    	return Queen
    }
    
    func main() {
    
    	Queen := NewQueen()
    	fmt.Println(Queen.slice) //打印空队列
    
    	Queen.enqueue(4)
    	fmt.Println(Queen.slice)
    
    	Queen.enqueue(6)
    	fmt.Println(Queen.slice)
    
    	Queen.enqueue(2)
    	fmt.Println(Queen.slice)
    
    	fmt.Println(Queen.dequeue())
    	fmt.Println(Queen.slice)
    
    	Queen.enqueue(3)
    	fmt.Println(Queen.slice)
    
    	fmt.Println(Queen.dequeue())
    	fmt.Println(Queen.slice)
    }
    
    
    展开全文
  • 网站的树结构深度优先算法和实现广度优先算法和实现网站的树结构通过伯乐在线网站为例子:并且我们通过访问伯乐在线也可以发现,我们从任何一个子页面其实都可以返回到首页,所以当我们爬取页面的数据的时候就会...
    dfeff470f492f1f697188919621744b8.png
    • 网站的树结构
    • 深度优先算法和实现
    • 广度优先算法和实现

    网站的树结构

    通过伯乐在线网站为例子:

    3352648780f1e788a3d60ba6c8a6cf5f.png

    并且我们通过访问伯乐在线也是可以发现,我们从任何一个子页面其实都是可以返回到首页,所以当我们爬取页面的数据的时候就会涉及到去重的问题,我们需要将爬过的url记录下来,我们将上图进行更改

    76ac948f157852e1d50d60e496370d6a.png

    在爬虫系统中,待抓取URL队列是很重要的一部分,待抓取URL队列中的URL以什么样的顺序排队列也是一个很重要的问题,因为这涉及到先抓取哪个页面,后抓取哪个页面。而决定这些URL排列顺序的方法,叫做抓取策略。下面是常用的两种策略:深度优先、广度优先

    73df426c1d356bd8a569373f195124a2.png

    深度优先

    深度优先是指网络爬虫会从起始页开始,一个链接一个链接跟踪下去,处理完这条线路之后再转入下一个起始页,继续追踪链接,通过下图进行理解:

    注:scrapy默认采用的是深度优先算法

    447715e8515f2cc951066c689789cf25.png

    这里是深度优先,所以这里的爬取的顺序式:

    A-B-D-E-I-C-F-G-H (递归实现)

    深度优先算法的实现(伪代码):

    48aabb10f73a08184c143ce7c0e3486b.png

    广度优先

    广度优先,有人也叫宽度优先,是指将新下载网页发现的链接直接插入到待抓取URL队列的末尾,也就是指网络爬虫会先抓取起始页中的所有网页,然后在选择其中的一个连接网页,继续抓取在此网页中链接的所有网页,通过下图进行理解:

    4ccea50d5ce830b166165dfe470a8e86.png

    还是以这个图为例子,广度优先的爬取顺序为:

    A-B-C-D-E-F-G-H-I (队列实现)

    广度优先代码的实现(伪代码):

    23c5424d782ec80df852628757c10913.png

    所有的努力都值得期许,每一份梦想都应该灌溉!

    展开全文
  • 因此,可以枚举每一条边,假设最小生成树的值B, 而枚举的那条边长度edge[i][j], 如果这一条边已经属于最小生成树上的,那么最终式子的值A/(B-edge[i][j])。如果这一条不属于最小生成树上的, 那么添加上这...
  • 队列是什么 队列是一种先进先出(First-In-First-Out,Fifo)的数据结构。 队列是一种列表,不同的是队列只能在队尾插入元素,在队首删除元素。 队列用于存储按顺序排列的数据,先进先出,这点和栈不一样,在...
  • 队列是什么队列是一种先进先出(First-In-First-Out,Fifo)的数据结构。队列是一种列表,不同的是队列只能在队尾插入元素,在队首删除元素。队列用于存储按顺序排列的数据,先进先出,这点和栈不一样,在栈中,最后...
  • 对于上图的结构,通过广度优先搜索BFS找到两个节点Node之间的最近距离(比如A和G之间2) 1. 结点的处理顺序是什么? 在第一轮中,我们处理根结点。在第二轮中,我们处理根结点旁边的结点;在第三轮中,我们处理距...
  • 本文就以实现优先级队列(Priority Queue)为例,通过图片和人类的语言来描述一下二叉堆怎么运作的。 目录 1、二叉堆概览 2、优先级队列概览 3、实现 swim 和 sink 4、实现 delMax 和 ins...
  • 1、什么是优先队列 2、堆的基础表示   二叉堆的2个性质:   下面介绍二叉堆的实现技巧:使用数组存储二叉堆(当然,也可以像前面的二分搜索树那样,通过左右指针的指定某个结点的左右孩子) 3、二叉堆...
  • 栈(Stack)和队列(Queue)两种操作受限的线性表。 栈与队列的相同点: 1.都线性结构。 2.插入操作都限定在表尾进行。 3.都可以通过顺序结构和链式结构实现。、 4.插入与删除的时间复杂度都O(1),在空间...
  • 多线程的实现一、通过继承Thread实现线程(一)线程的调度线程调度的策略Java的调度方法线程的优先级控制(二)Thread类的常用方法(三 )通过继承Thread实现线程的例子 一、通过继承Thread实现线程 (一)线程的...
  • 本篇文章,将对队列进行一个深入的解析。使用场景队列在日常生活中十分常见,例如:银行排队办理业务、食堂排队打饭等等,这些都是队列的应用。...队列是一个有序列表,可以用数组或是链表来实现遵循...
  • 我们在介绍《什么是优先队列》的时候就注意到,如果每次都删除堆顶元素,那么将会得到一个有序的数据。因此,我们可以利用二叉堆来对数据进行排序。 堆排序分析 通过前面的学习我们可以看到,如果构建一个二叉堆,...
  • 队列1、什么是队列2、队列的基本操作【1】入队【2】出队循环队列循环队列代码实现3、队列的应用双端队列优先队列 1、什么是队列 假如公路上有一条单行隧道,所有通过隧道的车辆只允许从隧道入口驶入,从隧道出口驶出...
  • 深度优先和广度优先

    2018-11-14 19:52:53
    网站的树结构 深度优先算法和实现 广度优先算法和实现 网站的树结构 通过伯乐在线网站为例子: ...在爬虫系统中,待抓取URL队列是很重要的一部分,待抓取URL队列中的URL以什么样的顺序排队列也是一个很...
  • 深度优先搜索通过栈来实现,而广度优先搜索通过队列实现。 (一)广度优先搜索(BFS) 广度优先搜索最简单的图搜索算法之一,属于一种盲目搜寻法,目的系统地展开并检查图中的所有节点,以找寻结果。...
  • 本文主要讲的是实现最大堆,最小堆其实直接可以通过最大堆对比较运算做一定的处理,即可以得到。同时可以参考 Java PriorityQueue 的实现。堆可以作为优先队列。时间复杂度 O(logn)为什么使用堆?堆的 API 定义2....
  • 在爬虫系统中,待抓取URL队列是很重要的一部分,待抓取URL队列中的URL以什么样的顺序排队列也是一个很重要的问题,因为这涉及到先抓取哪个页面,后抓取哪个页面。而决定这些URL排列顺序的方法,叫做抓取策略。下面是...
  • 网站的树结构深度优先算法和实现广度优先算法和实现 网站的树结构 通过伯乐在线网站为例子:     并且我们通过访问伯乐在线也是可以...在爬虫系统中,待抓取URL队列是很重要的一部分,待抓取URL队列中的URL以什么
  • 网站的树结构深度优先算法和实现广度优先算法和实现网站的树结构通过伯乐在线网站为例子:并且我们通过访问伯乐在线也可以发现,我们从任何一个子页面其实都可以返回到首页,所以当我们爬取页面的数据的时候就会...
  • 网站的树结构 深度优先算法和实现 广度优先算法和实现 网站的树结构 通过伯乐在线网站为例子: ...在爬虫系统中,待抓取URL队列是很重要的一部分,待抓取URL队列中的URL以什么样的顺序排队列也...
  • 网站的树结构深度优先算法和实现广度优先算法和实现网站的树结构通过伯乐在线网站为例子:并且我们通过访问伯乐在线也可以发现,我们从任何一个子页面其实都可以返回到首页,所以当我们爬取页面的数据的时候就会...
  • BFS,通俗来讲,就是广度优先搜索,它可以通过队列实现。 也上面的图片的例子: BFS的其中一个结果就是:ABCDEF, 概括来说,就是把每个的相关点都依次的写出来。 2.DFS和BFS的代码实现 DFS的代码实现
  • java基础巩固(第二天)(栈、队列、泛型): 栈:一种“操作受限”的线性表;只允许在一端进行删除和插入。...栈既可以通过数组实现,也可以通过链表来实现。不管基于数组还是链表,入栈、出栈的时间复杂度都为 O(1
  • 什么是BFS? BFS比较常用的搜索算法,全名为Breadth First Search(广度优先算法),相当于在考虑问题的时候,可以将所有下一步会遇到的情况考虑好,然后推演每一步直到走到想要的结果。 应用场景 1.求出到达指定目标的...
  • 堆的主要用途在处理优先队列上,相比于普通队列的先进先出,后进后出,优先队列出队顺序和入队顺序无关,只和优先级有关。比如头等舱登机就比普通乘客先登机,而和先来后到没有关系。但是有人会说我把数组先进行...

空空如也

空空如也

1 2 3 4 5
收藏数 100
精华内容 40
关键字:

优先队列是通过什么实现的