看图说话数据结构之二项队列(优先队列)——原理解析

数据结构之二叉堆(优先队列)——原理解析数据结构之二叉堆(优先队列)——java实现数据结构之左式堆(优先队列)——原理解析及java实现三篇文章详细介绍了实现优先队列的两种数据结构:二叉堆和左式堆,本文在上述的基础上介绍优先队列的另外一种支持高效合并操作的实现——二项队列。原来在介绍二叉堆和左式堆的时候喜欢从结构性和堆序性两个方面介绍,它们二者都是特殊的二叉树结构,但是二项队列不能单纯的从结构性和堆序性两个方面介绍了因为二项队列并不是我们熟悉的树结构,而是树的集合——森林,本篇文章从二项队列的结构性出发介绍二项队列的基本原理。

一丶二项队列的结构性

    二项队列是一群树的集合,是森林,是特殊的森林。这个森林的特殊之处在于组成森林的树都是二项树,下图就是最为典型的二项队列。

图1 典型的二项队列

    图1所示的是一个典型的二项队列,它是由四课树组成的森林,接下里对应图1所示的结构介绍二项队列具有的性质和特点。

  • 二项树,观察图1中的四棵树,若不考虑节点数值的因素,可以看出树2是由两个树1拼凑而成的,其中一个树1结构充当另外一个树1的右子树。观察树3同样也是如此,是一颗树2充当了另外一颗树2的右子树生成而来,同理可见树4。依据上述规律所生成的树都称为二项树,树1,树2,树3,树4均是二项树。根据二项树的生成规律,不难知道高度为i的二项树的结构是固定的,其节点总数为2^(i-1)个。

  • 二项队列从结构上来说是由高度不重复的若干个二项树构成的森林,高度不重复意味着相同高度的二项树在二项队列中最多存在一个。这里特别要注意二项队列中的二项树的高度不强制是连续的,比如高度为2的二项树不存在,高度为5的二项树却存在。

  • 从结构上来研究二项队列,其实二项队列还具有一个特别有意思的性质,若二项队列的总节点数已知道,那么二项队列的结构就是确定的。比如已知二项队列中的总节点树是15,想二项树的节点数,只有一种组合8+4+2+1,二项队列结构如下。


    图2 典型二项队列

    其实也很好理解,二项队列总节点数15,表示为二进制就是1111,二项树的节点数正好符合二进制上每位的权值。

二丶二项队列的“堆序性”

    假如一个森林,仅仅满足了上述的结构性,那它也还不是二项队列,毕竟二项队列是优先队列的一种实现,无论如何也是需要具备和二叉堆和左式堆一样的堆序性质的。同样借助图1来介绍二项队列所具备的”堆序性质”。

  • 组成二项队列的所有二项树都具有一致的堆序性,每一个二项树不仅仅满足堆序性,而且每个二项树的堆序性必须保持一致,要么都是大根堆,要么就是小根堆。
三丶二项队列的建堆操作

    合并操作是二项队列中的核心操作,在合并操作的基础上可以轻易的实现插入操作,因为插入操作可以理解为节点数为1的二项队列的合并操作,而建堆操作则可以理解为一系列的插入操作。接下里利用图例的形式来讲解二项队列的建堆操作,借用建堆的过程来清晰的阐述合并操作和插入操作。待建堆的操作如下,构建一个低优先级先出队的二项队列。

             int[]A = new{5,4,3,2,1,9,7 }待建立二项队列的数组元素                  
  1. 在实现二项队列的合并操作之前,需要特别说明二项队列的森林结构是利用一个节点数组来存储的,数组当中的每一个节点都代表一个二项树的根。对于节点数为N的二项队列而言,其二项树的个数可计算为Log(N),对数组大小的分配具体参加Log(N),此处为了简单数组的大小分配为:Math.ceil(Log(N))+1=4,HeapNode [] item = new HeapNode[4]。HeapNode是二项树节点定义。

如图所示:


图3 初始二项队列
  1. 对于数组A而言,入队第一个元素A[0] = 5,取二项队列数组的第一个元素item[0],依据item[0]是否为空来采取后续措施,如下伪代码所示。
if(item[0]==null)
  item[0]= new HeapNode(A[0]);
else
  merge(item[0],newHeapNode(A[0]));

依据如上的伪代码此次执行的是if下的逻辑,入队后结果如下:


图4元素5入队结果
  1. 继续入队第二个元素A[1] = 4,同样的取出二项队列的第一元素item[0],带入步骤2的伪代码逻辑,发现执行merge(item[0],newHeapNode[A[1]])逻辑,重点来了,此时执行的是merge(合并)逻辑,合并的对象是两个只包含根节点的二项树,将根节点较大的二项树,充当根节点较小的二项树的子树,合并完成,结果如下


    图5元素4入队结果

        如图5所示,原有的两个二项树合并成了一个新的二项树,但是此时合并操作并没有结束,新合并的二项树不能存放在原有数组的位置,其存放的数组下标+1.调整结果如下。


    图6 元素4插入二项队列的最终结果
  2. 继续入队第三个元素3,重复步骤2,结果如图7所示


    图7元素3插入二项队列的最终结果
  3. 继续入队第四个元素2,重复步骤2,发现Item[0]处存在元素,则重复步骤3,在步骤3中发现一个新问题,如下图所示:


    图8 元素2入队的中间结果

        如图5所示,原有的两个二项树合并成了一个新的二项树,但是此时合并如上图所示,元素2插入后需要和元素3进行合并,并且将合并的结果存到下标+1处即下标为1处,但是发现下标为1的地方以存在一个二项树,此时需要继续合并,将下标为1处的原二项树和新合并产生的二项树进行合并,合并结果如下:


    图9 元素2的入队最终结果。

        观察图9所示的结果,可以发现合并后高度为3的二项树,同样不存放在其原有的位置,而是存在其原有位置的下标+1处。其建立二项队列操作介绍到此处,可以发现在二项队列的数组中,二项树的高度和存储位置的索引一一对应,高度为1的二项树,存在下标为0处,高度为2的二项树存在下标为1处,高度为3的二项树存在下标为3处,依次类推高度为i的二项树,存在下标为i-1处。
  4. 继续入队第五个元素1,重复步骤2,入队结果如下图所示
    图10元素1的入队结果
  5. 继续入队第6个元素9,重复步骤2。结果如下:


    图11 元素9的入队结果
  6. 继续入队第7个元素7,重复步骤2.结果如下:


    图12元素7的入队结果

         依据上述的8个步骤,十分清晰的了解了二项队列的建队操作,为了进一步的加深对二项队列的认识,下面来介绍一下二项队列的合并操作。

四丶二项队列的合并操作。

    在上述的二项队列建队操作中,其实每一次插入操作都是特殊的合并操作,
    都可以看成一个节点的二项队列的特殊合并操作。二项队列的合并过程其实用一句话就可以描述——将高度相同的二项树合并。此处采用两个简单的二项队列来阐述两个二项队列合并的具体实现过程。


图13 待合并的两个二项队列

(1) 如图13所示两个待合并的二项队列,在合并的过程中维护这一个指针i,i的初始值指向第一个元素i=0,这里假设合并的过程是h2并入h1的过程。分别取出h1和h2中第i个元素,发现h2对应的元素是null,不做处理,i++,结果如下。


图14合并第一步

(2)和步骤1的处理相同,分别取出两队列中第i=1个位置的二项树,均不为空,所以合并这两个子树,合并的结果存放到i+1=2处的位置,同时删除原队列中第i=1个位置的二项树,i++。在此过程中出现了冲突,第个i=2位置存在了二项树,处理的方法和插入过程中处理合并的方法保持一致。合并结果如下:
图15 合并第二步

(3)如图15,此时i=2,两个二项队列分别取出第i个位置的二项树,发现h1中为null,h2不为null,所以此时直接利用h2中的二项树去覆盖h1中的第i个位置就行,然后删除h2中的二项树,i++,结果如下图所示。
图16合并第三步。

(4)指针i移动完毕,该次合并结束。

五丶二项队列的删除操作

    在了解二项队列的合并操作后,理解二项队列的删除操作就十分简单了,假设待删除二项队列为H1,步骤如下:

  1. 遍历H1中的数组,找到根节点值最小的二项树tree1,其根节点值就是出队值。

  2. 从H1数组中删除该二项树tree1,将删除tree1后的二项队列记为H2.

  3. 对于二项树tree1,删除其根节点,利用其子树d1,d2,d3….组成一个新的二项队列H3。

  4. 合并H2和H3,合并后的二项队列就是删除操作后的二项队列。

    在详细的了解二项队列建队,删除,和插入操作后,可以给出二项队列操作的时间复杂度(不做分析证明)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容