日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

优先队列——二项队列(binominal queue)

發布時間:2023/12/3 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 优先队列——二项队列(binominal queue) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【0】README

0.1) 本文文字描述部分轉自 數據結構與算法分析, 旨在理解 優先隊列——二項隊列(binominal queue) 的基礎知識;
0.2) 本文核心的剖析思路均為原創(insert,merge和deleteMin的操作步驟圖片示例), 源代碼均為原創
0.3) for original source code, please visit https://github.com/pacosonTang/dataStructure-algorithmAnalysis/tree/master/chapter6/p152_binominal_queue


【1】二項隊列相關

1.0)Attention: 二項隊列中不允許有高度相同的二項樹存在該隊列中;
1.1)problem+solution:

  • 1.1.1)problem:雖然左式堆和斜堆每次操作花費O(logN)時間, 這有效地支持了合并, 插入和deleteMin, 但還是有改進的余地,因為我們知道, 二叉堆以每次操作花費常數平均時間支持插入。
  • 1.1.2)solution: 二項隊列支持所有這三種操作(merge + insert + deleteMin), 每次操作的最壞情形運行時間為O(logN), 而插入操作平均花費常數時間; (干貨——優先隊列的三種基本操作——merge + insert + deleteMin)

1.2)相關定義

  • 1.2.1) 二項隊列定義: 二項隊列不同于我們看到的所有優先隊列的實現之處在于, 一個二項隊列不是一顆堆序的樹, 而是堆序樹的集合,稱為森林;(干貨——二項隊列的定義和構成,二項隊列是二項樹的集合,而二項樹是一顆堆序樹)
  • 1.2.2)二項樹定義: 堆序樹中的每一顆都是有約束的形式。 (干貨——二項樹的定義)
  • 1.2.3)二項樹的構成:每一個高度上至多存在一顆二項樹, 高度為0的二項樹是一顆單節點樹; 高度為k 的二項樹Bk 通過將一顆二項樹 Bk-1 附接到另一顆二項樹Bk-1 的根上而構成;(干貨——二項樹的構成)

對上圖的分析(Analysis):

  • A1)二項樹的性質:

    • A1.1)從圖中看到, 二項樹Bk 由一個帶有兒子B0, B1, …, Bk-1的根組成;
    • A1.2)高度為k 的二項樹恰好有2^k 個節點;
    • A1.3) 而在深度d 的節點數是 二項系數 。
  • A2)如果我們把堆序添加到二項樹上, 并允許任意高度上最多有一顆二項樹,那么我們能夠用二項樹的集合唯一地表示任意大小的優先隊列;


【2】二項隊列操作(merge + insert + deleteMin)

2.1)合并操作(merge) (干貨——合并操作的第一步就是查看是否有高度相同的二項樹,如果有的話將它們merge)

  • step1) H1 沒有高度為0的二項樹而H2有,所以將H2中高度為0的二項樹直接作為H3的一部分;(直接的意思==中間不需要merge);
  • step2) H1 和 H2 中都有高度為1的二項樹,將它們進行merge, 得到高度為2的二項樹(根為12);
  • step3)現在存在三顆高度為2的二項樹(根分別為12, 14, 23),將其中兩個進行merge(如merge根為12 和 根為14 的二項樹),得到高度為3的二項樹;
  • step4)所以,最后,我們得到二項隊列, 其集合包括:高度為0的二項樹(根為13), 高度為1的二項樹(根為23),高度為3的二項樹(高度為12);

Attention)

  • A1)顯然,merge操作是按照高度升序依次進行的;
  • A2)最后得到的二項隊列不存在高度相同的二項樹,即使存在,也要將高度相同的二項樹進行merge;
  • A3)二項隊里中的二項樹的高度不必囊括所有的升序實數,即不必一定是0, 1, 2, 3,4 等等; 也可以是0, 1, 3 等;
  • A4)單節點樹的高度為0; (干貨——樹高度從零起跳)

2.2)插入操作(insert) (干貨——insert操作是merge操作的特例,而merge操作的第一步就是查看是否有高度相同的二項樹,如果有的話將它們merge)

  • 2.2.1)插入操作實際上: 就是特殊情形的合并, 我們只需要創建一顆單節點樹并執行一次merge;
  • 2.2.2)更準確地說: 如果元素將要插入的那個優先隊列中不存在的最小的二項樹是Bi, 那么運行時間與 i + 1 成正比;

對上圖的分析(Analysis):

  • A1) 4 插入之后,與B0(根為3)進行merge, 得到一顆高度為1的樹B1’(根為3);
  • A2)將B1’ 與 B1(根為1) 進行merge 得到高度為2 的樹B2’(根為1), 它是新的優先隊列;
  • A3)在插入7之后的下一次插入又是一個壞情形, 因為需要三次merge操作;

2.3)刪除最小值操作(deleteMin)

  • step1)找出一顆具有最小根的二項樹來完成, 令該樹為Bk, 令原始序列為H;
  • step2)從H中除去Bk, 形成新的二項隊列H’;
  • step3)再除去Bk的根, 得到一些二項樹B0, B1, …, Bk-1, 它們共同形成優先隊列H”;
  • step4) 合并H’ 和 H” , 操作結束;

【3】 source code and printing results

3.1)source code at a glance
Attention)二項隊列的實現源代碼用到了 兒子兄弟表示法

#include "binominal_queue.h" #define MINIMAL 10000int minimal(BinominalQueue bq) {int capacity;int i;int minimal;int miniIndex; minimal = MINIMAL;capacity = bq->capacity;for(i=0; i<capacity; i++){if(bq->trees[i] && bq->trees[i]->value < minimal){minimal = bq->trees[i]->value;miniIndex = i;}}return miniIndex; }// initialize the BinominalQueue with given capacity. BinominalQueue init(int capacity) {BinominalQueue queue; BinominalTree* trees; int i;queue = (BinominalQueue)malloc(sizeof(struct BinominalQueue));if(!queue){Error("failed init, for out of space !");return queue;} queue->capacity = capacity;trees = (BinominalTree*)malloc(capacity * sizeof(BinominalTree));if(!trees){Error("failed init, for out of space !");return NULL;} queue->trees = trees;for(i=0; i<capacity; i++){queue->trees[i] = NULL;}return queue; } // attention: the root must be the left child of the binominal tree. int getHeight(BinominalTree root) {int height; if(root == NULL){ return 0; }height = 1; while(root->nextSibling){height++;root = root->nextSibling;}return height; }// merge BinominalQueue bq2 into bq1. void outerMerge(BinominalQueue bq1, BinominalQueue bq2) {int height;int i;for(i=0; i<bq2->capacity; i++){height = -1;if(bq2->trees[i]){height = getHeight(bq2->trees[i]->leftChild); // attention for the line above// height = height(bq2->trees[i]->leftChild); not height = height(bq2->trees[i]);merge(bq2->trees[i], height, bq1);} } }// merge tree h1 and h2 = bq->trees[height], // who represents the new tree and old one respectively. BinominalTree merge(BinominalTree h1, int height, BinominalQueue bq) { if(h1 == NULL){return h1;}if(bq->trees[height] == NULL) // if the queue don't has the B0 tree.{ bq->trees[height] = h1;return bq->trees[height];}else // otherwise, compare the new tree's height with that of old one.{ if(h1->value > bq->trees[height]->value) // the new should be treated as the parent of the old.{ innerMerge(bq->trees[height], height, h1, bq);}else // the old should be treated as the parent of the new.{innerMerge(h1, height, bq->trees[height], bq);}} return h1; } BinominalTree lastChild(BinominalTree root) { while(root->nextSibling){ root = root->nextSibling;}return root; }// merge tree h1 and h2 = bq->trees[height], // who represents the new tree and old one respectively. BinominalTree innerMerge(BinominalTree h1, int height, BinominalTree h2, BinominalQueue bq) {if(h1->leftChild == NULL){h1->leftChild = h2;}else{lastChild(h1->leftChild)->nextSibling = h2;// attention for the line above// lastChild(h1->leftChild)->nextSibling = h2 not lastChild(h1)->nextSibling = h2}height++;bq->trees[height-1] = NULL;merge(h1, height, bq); return h1; } // insert an element with value into the priority queue. void insert(ElementType value, BinominalQueue bq) {TreeNode node;node = (TreeNode)malloc(sizeof(struct TreeNode));if(!node){Error("failed inserting, for out of space !");return ;}node->leftChild= NULL;node->nextSibling = NULL; node->value = value; merge(node, 0, bq); }// analog print node values in the binominal tree, which involves preorder traversal. void printPreorderChildSibling(int depth, BinominalTree root) { int i;if(root) { for(i = 0; i < depth; i++)printf(" ");printf("%d\n", root->value); printPreorderChildSibling(depth + 1, root->leftChild); printPreorderChildSibling(depth, root->nextSibling);} else{for(i = 0; i < depth; i++)printf(" ");printf("NULL\n");} }// print Binominal Queue bq void printBinominalQueue(BinominalQueue bq) {int i;for(i=0; i<bq->capacity; i++){printf("bq[%d] = \n", i);printPreorderChildSibling(1, bq->trees[i]);} }void deleteMin(BinominalQueue bq) {int i; BinominalTree minitree; BinominalTree sibling;i = minimal(bq);minitree = bq->trees[i]->leftChild; //minitree->value=51free(bq->trees[i]);bq->trees[i] = NULL; while(minitree){sibling = minitree->nextSibling;minitree->nextSibling = NULL;merge(minitree, getHeight(minitree->leftChild), bq); minitree = sibling;} }

3.2) printing results

總結

以上是生活随笔為你收集整理的优先队列——二项队列(binominal queue)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。