这是算法与数据结构番外系列的第一篇,这个系列未来的主要内容是补充一些与算法与数据结构相关的知识,这些知识比较零碎,同时也与正传关系密切,往往需要阅读了正传的相关内容以后,才能较好的理解这部分内容。如果对番外系列不感兴趣的话,是可以跳过此系列内容的,不会影响理解其他文章的内容。

阅读本文前,需要首先了解队列和堆的相关知识。

此文优先队列的代码可以在我的 github 上查看。

优先队列

优先队列是一种特殊的队列。队列具有先进先出的特性,对于普通队列而言,首先出队的元素是首先入队的元素,而优先队列中,首先出队的元素是目前队列中优先级最高的元素。

优先队列分为两类,最大优先队列和最小优先队列。一个最大优先队列的严格定义如下:

> 最大优先队列是一种用来维护由一组元素构成的集合 S 的数据结构,其中的每一个元素都有一个相关的值,称为关键字(key,也就是我们上文所说的优先级),一个最大优先队列应该支持以下操作:

>

> INSERT(S, x):把元素 x 插入集合 S 中。

>

> MAXIMUM(S):返回 S 中具有最大关键字的元素。

>

> EXTRACT-MAX(S):去掉并返回 S 中的具有最大关键字的元素。

最大优先队列最为著名的应用场景,是共享计算机系统的作业调度。最大优先队列将会记录将要执行的各个作业以及它们之间的相对优先级。当一个作业完成或者被中断后,调度器调用 EXTRACT-MAX 从所有的等待作业中,选出具有最高优先级的作业来执行,在任何时候,调度器都可以调用 INSERT 把一个新作业加入到队列中来。

相应的,最小优先队列则是选择集合中具有最小关键字的元素。最小优先队列经常被用于模拟。队列中保存要模拟的事件,每个事件都有一个发生时间作为其关键字,事件将会按照时间先后顺序依次发生。模拟程序调用 EXTRACT-MIN (即与 EXTRACT-MAX 正好相反的功能:去掉并返回 S 中的具有最小关键字的元素)选择下一个要模拟的事件,当一个新事件产生时,模拟器通过调用 INSERT 将其插入最小优先队列。

优先队列可以使用堆来实现,最大优先队列对应最大堆,最小优先队列对应最小堆。下面我们将以最大优先队列为例进行介绍。

优先队列的实现

优先队列的定义

优先队列的定义与队列几乎完全一样:

// 优先队列定义

typedef struct PriorityQueue{

int* array;

int max_size;

}PriorityQueue;

辅助函数

这些辅助函数我们在堆排序的那一章中已经写好,这里可以直接使用。

获取堆中节点的父节点,左孩子和右孩子节点下标:

#define PARENT(i) (i / 2)

#define LEFT(i) (2 * i)

#define RIGHT(i) (2 * i + 1)

交换数组两个元素的值:

// 交换数组 下标i 和 下标j 对应的值

int swap(int *array, int i, int j){

int temp;

temp = array[i];

array[i] = array[j];

array[j] = temp;

return 0;

}

递归维护最大堆:

// 递归维护最大堆

int MaintainMaxHeap(int *heap, int i){

int largest;

int left = LEFT(i);

int right = RIGHT(i);

if(left <= heap[0] && heap[left] > heap[i]){

largest = left;

} else{

largest = i;

}

if(right <= heap[0] && heap[right] > heap[largest]){

largest = right;

}

if(largest != i){

swap(heap, largest, i);

MaintainMaxHeap(heap, largest);

}

return 0;

}

这些辅助函数是直接采用的堆排序所用代码,由于篇幅有限,故不再重复解释,可以点此查看相关解释。

初始化函数

// 初始化优先队列

PriorityQueue* PriorityQueueInit(int max_size){

PriorityQueue* priority_queue = (PriorityQueue*)malloc(sizeof(PriorityQueue));

priority_queue->array = (int*)malloc(sizeof(int) * (max_size + 1));

priority_queue->array[0] = 0;

priority_queue->max_size = max_size;

return priority_queue;

}

我们在这里,依然使用堆排序中的数组解释方法:array[0] 用于储存堆中的有效数据个数,故数组的实际长度为 max_size + 1,堆顶元素是 array[1]。

入队函数

// 优先队列入队

int PriorityQueueEnqueue(PriorityQueue *priority_queue, int number_to_enqueue){

int i;

priority_queue->array[0] += 1;

i = priority_queue->array[0];

priority_queue->array[priority_queue->array[0]] = number_to_enqueue;

while(i > 1 && priority_queue->array[PARENT(i)] < priority_queue->array[i]){

swap(priority_queue->array, PARENT(i), i);

}

return 0;

}

整个最大优先队列本质上是一个最大堆,当我们插入一个数据时,首先将其插入至堆的尾部,此时可能会违背最大堆的性质,故我们将此元素不断与其父节点的值进行比较,若其小于父节点的值,说明此时整个堆已经是一个最大堆了;若其大于父节点的值,则将此节点与父节点交换,重复此步骤,直到此元素小于其父节点的值或此元素成为了堆顶节点。

显然,入队操作的时间复杂度是 $O(lgn)$ ,因为整个函数中影响其时间复杂度的过程为 while 循环,其最差情况是将此元素从叶节点一步一步交换至根节点,而树的高度为 $O(lgn)$ 。

整个过程如下图所示:

出队函数

// 优先队列队首元素

int PriorityQueueHead(PriorityQueue *priority_queue){

return priority_queue->array[1];

}

// 优先队列出队

int PriorityQueueDequeue(PriorityQueue *priority_queue){

int return_number = priority_queue->array[1];

priority_queue->array[1] = priority_queue->array[priority_queue->array[0]];

priority_queue->array[0] -= 1;

MaintainMaxHeap(priority_queue->array, 1);

return return_number;

}

在理解了堆排序以后,优先队列的出队操作很简单了。

一个最大优先队列出队时返回的值为队列中的最大值,即 array[1],那么我们只需要像堆排序时那样,将堆中最后一个有效数据复制到堆顶(array[1]),此时新的堆顶可能会违反最大堆的性质,为此我们只需对堆顶元素调用一次 MaintainMaxHeap() ,即可保证出队后,此堆依然是一个最大堆。

关于此过程的时间复杂度和正确性分析,我们已经在堆排序一章中介绍过了,在此就不赘述了,直接给出结果 $O(lgn)$ 。

总结

在理解了堆排序以后,优先队列就非常简单了,几乎连代码都不需要太多修改。从上文的分析,我们也能得出一个结论,优先队列最为关键的两个步骤(入队、出队)的时间复杂度均为 $O(lgn)$ 。

原文链接:albertcode.info

个人博客:albertcode.info

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[算法与数据结构番外(1):优先队列]http://www.zyiz.net/tech/detail-132619.html

java优先队列的入队函数,算法与数据结构番外(1):优先队列相关推荐

  1. Java并发(五)线程池使用番外-分析RejectedExecutionException异常

    Java并发(五)线程池使用番外-分析RejectedExecutionException异常 参考文章: (1)Java并发(五)线程池使用番外-分析RejectedExecutionExcepti ...

  2. 白话机器学习算法理论+实战番外篇之LightGBM

    1. 写在前面 如果想从事数据挖掘或者机器学习的工作,掌握常用的机器学习算法是非常有必要的,在这简单的先捋一捋, 常见的机器学习算法: 监督学习算法:逻辑回归,线性回归,决策树,朴素贝叶斯,K近邻,支 ...

  3. java优先队列的入队函数_Java内置的优先队列PriorityQueue

    PriorityQueue是Java内置的优先队列,每次取出来的元素是最小的.PriorityQueue可以做到自动扩容.PriorityQueue中的对象必须是可比较的. 例如,最简单的情况,在Pr ...

  4. 【C++】C++11 STL算法(九):番外篇

    1.如果获取指针或迭代器指向的类型 详见:C 11:如何获取一个指针或迭代器指向的类型? decltype(*std::declval<Pointer>()) decltype:c++11 ...

  5. JAVA sleep函数如何用_转载:java中Thread.sleep()函数使用

    Java多线程系列更新中~ 正式篇: 番外篇(神TM番外篇): 我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间.那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题: 假 ...

  6. 痞子衡嵌入式:超级下载算法(RT-UFL)开发笔记番外(1) - JLinkScript妙用

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是超级下载算法开发笔记番外篇之JLinkScript妙用. JLinkScript 文件是配套 J-Link 调试器使用的脚本,这个脚本适 ...

  7. 格雷通路 算法 java,Java算法与数据结构教程

    北上广容不下肉身, 三四线放不下灵魂, 程序员里没有穷人, 有一种土豪叫 算法工程师. 程序 = 数据结构 + 算法 程序是为了解决实际问题而存在的.然而为了解决问题,必定会使用到某些数据结构以及设计 ...

  8. 数据结构与算法——常用数据结构及其Java实现

    前言 仿佛一下子,2017年就快过去一半了,研一马上就要成为过去式了,我打算抓住研一的尾巴,好好梳理一下数据结构与算法,毕竟这些基础知识是很重要的嘛.所以准备在这里搞一个系列的文章,以期透彻. 本系列 ...

  9. (java)玩转算法系列-数据结构精讲[学习笔记](一)不要小瞧数组

    前言: 课程:玩转算法系列–数据结构精讲 更适合0算法基础入门到进阶(java版) 此处是个人学习笔记,用作回顾用途 不要小瞧数组 1.使用java中的数组 Main.java: public cla ...

最新文章

  1. 英文句子改写在线软件_试完这些英文论文写作辅助神器,你会发现新大陆der~...
  2. Scribe日志收集工具
  3. Java集合Vector
  4. 谷歌浏览器flash_谷歌浏览器不支持Flash Player的问题
  5. 所谓语音合成 是计算机根据语言学,计算语言学完整1
  6. LeetCode 1562. 查找大小为 M 的最新分组
  7. IT NEWS WebSite
  8. CentOS7安装xrdp(windows远程桌面连接CentOS)
  9. 如何利用回调模式去解决问题
  10. mac系统下设置eclipse的补全快捷键方法
  11. 数百种 Windows 软件的免费替代品列表(转)
  12. 一键备份服务器文件夹权限,教大家一键设置局域网共享文件夹权限
  13. gitlab: [remote rejected] pre-receive hook declined
  14. 慧鱼机器人编程18子程序
  15. 6.4 置换基本概念
  16. Excel-VBA基础(7):VBE开发环境的主要优化配置
  17. 篆刻小站之设计与开发
  18. 在列表中正数和负数区分出来,并且对它们进行分列
  19. 团体程序设计天梯赛-练习集 1-2 打台球(5 分)
  20. 解决PowerBuilder错误:unable to load the requested database interface please

热门文章

  1. Replication--镜像+复制
  2. Elasticsearch - 索引管理
  3. 大数据开发实战:Hive表DDL和DML
  4. VConsole的使用
  5. 入手ipod touch4
  6. xenserver 管理口显示重复IP的处理方法
  7. vs2010往oracle 10g中插入数据
  8. qq在线咨询代码,MSN在线代码,贸易通在线留言源代码!
  9. 华为rh2285安装系统linux,华为2285h v5安装系统记
  10. windows失败计算机关闭,win10电脑关机失败怎么办|win10系统正确关机的详细方法