左式堆和斜堆已经很好的支持了插入、合并以及删除且都是级别。二项队列也支持这三种操作,且插入操作平均花费常数时间。
定义
- 二项队列不是堆,是堆的 collection ,每个堆都是二叉树

有
个儿子,
个节点,深度为
处有
个节点
-
结构
任意大小的堆都可以表示成二项树的 collection。

由于二项队列的结构较为特殊,有很多儿子,为了删除的快速和方便,我们用儿子-兄弟结构存放二项队列;为了合并的方便,从左到右子树按高度降序(descending)排列。
操作
Merge & Insert
很像合成大西瓜……

插入是合并的特殊情况,不多赘述。可以看出合并时实际上也是在做二进制加法,这启发我们代码也可以这样写: ```cpp / merge equal-sized T1 and T2 / //实际做合并的驱动程序 BinTree CombineTrees( BinTree T1, BinTree T2 ){
/ attach the larger one to the smaller one / if ( T1->Element > T2->Element ){return CombineTrees( T2, T1 );
}
/ insert T2 to the front of the children list of T1 / T2->NextSibling = T1->LeftChild; T1->LeftChild = T2;
return T1; }
BinQueue Merge( BinQueue H1, BinQueue H2 ){
BinTree T1, T2, Carry = NULL;
int i, j; //j是计数器
if ( H1->CurrentSize + H2-> CurrentSize > Capacity ){ErrorMessage();}H1->CurrentSize += H2-> CurrentSize;for ( i=0, j=1; j<= H1->CurrentSize; i++, j*=2 ) {T1 = H1->TheTrees[i]; T2 = H2->TheTrees[i]; /*current trees *//* Carry T2 T1 *///这里巧妙的一点是把指针用!!转化为0和1来计算switch( 4*!!Carry + 2*!!T2 + !!T1 ) {case 0: /* 000 */case 1: /* 001 */ break; //这两种情况都不需要合并case 2: /* 010 */H1->TheTrees[i] = T2;H2->TheTrees[i] = NULL;break;case 4: /* 100 */H1->TheTrees[i] = Carry;Carry = NULL;break;case 3: /* 011 */Carry = CombineTrees( T1, T2 );H1->TheTrees[i] = H2->TheTrees[i] = NULL;break;case 5: /* 101 */Carry = CombineTrees( T1, Carry );H1->TheTrees[i] = NULL;break;case 6: /* 110 */Carry = CombineTrees( T2, Carry );H2->TheTrees[i] = NULL;break;case 7: /* 111 */H1->TheTrees[i] = Carry;Carry = CombineTrees( T1, T2 );H2->TheTrees[i] = NULL;break;} /* end switch */} /* end for-loop */return H1;
}
<a name="jVoUS"></a>## DeleteMin删除复杂一些,不过蕴含了合并操作<br />```cppElementType DeleteMin( BinQueue H ){BinQueue DeletedQueue;Position DeletedTree, OldRoot;/* the minimum item to be returned */ElementType MinItem = Infinity;/* MinTree is the index of the tree with the minimum item */int i, j, MinTree;if ( IsEmpty( H ) ) {PrintErrorMessage();return –Infinity;}/* Step 1: find the minimum item */for ( i = 0; i < MaxTrees; i++) {if( H->TheTrees[i] && H->TheTrees[i]->Element < MinItem ) {MinItem = H->TheTrees[i]->Element; MinTree = i;}}DeletedTree = H->TheTrees[ MinTree ];/* Step 2: remove the MinTree from H => H’ */H->TheTrees[ MinTree ] = NULL;/* Step 3.1: remove the root */OldRoot = DeletedTree;DeletedTree = DeletedTree->LeftChild;free(OldRoot);/* Step 3.2: create H” */DeletedQueue = Initialize();DeletedQueue->CurrentSize = ( 1<<MinTree ) – 1; /* 2^MinTree – 1 *///这里的做法是将删除元素后产生的子树先整理成二项队列,以便后续合并for ( j = MinTree – 1; j >= 0; j – – ) {DeletedQueue->TheTrees[j] = DeletedTree;DeletedTree = DeletedTree->NextSibling;DeletedQueue->TheTrees[j]->NextSibling = NULL;}H->CurrentSize –= DeletedQueue->CurrentSize + 1;/* Step 4: merge H’ and H” */H = Merge( H, DeletedQueue );return MinItem;}
摊还分析



