数据结构--二项队列的思想与实现

二项队列不是一颗堆序的树,而是堆序树的集合,称为森林,森林中每棵树都是有约束的形式,称为二项树,高度为k的第k个二项树Bk由一个根节点和B0, B1, .......B(k-1)构成,高度为k的二项树的结点个数为2^k,因此可以用二项树的结合表示任意大小的优先队列。例如,大小为13的优先队列就可以用B3,B2,B0来表示,2^0+2^2+2^3 = 13.因此二进制的表示为1101。

例如,二项树B0,B1,B2,B3表示如下:

把所有二项树的根节点按规律放在一个根节点组成的数组中,就组成二项队列,如下图所示:

二项队列也是优先队列的一种,其基本操作就是合并操作和删除最小元操作,本文给出的代码还包括插入,和查找操作,代码如下:

#include<iostream>

using namespace std;

typedef struct BinNode *Position;
typedef struct BinNode *BinTree;
typedef struct Collection *BinQueue;

#define MaxTrees  30
#define Capacity  ((1<<MaxTrees)-1)   //为2^0+2^1+2^2+2^(MaxTrees-1)
#define Infinity 65536

struct BinNode
{
   int Element;
   Position LeftChild;
   Position NextSibling;
};

struct Collection
{
   int CurrentSize;      //二项队列中节点的个数
   BinTree TheTrees[MaxTrees];
};

BinQueue Initialize()
{
BinQueue H = (BinQueue)malloc(sizeof(struct Collection));
    if (H == NULL)
        cout << "out of space" <<endl;
    for (int i = 0; i < MaxTrees; i++)
		H->TheTrees [i] = NULL;
    H->CurrentSize  = 0;
    return H;
}

BinTree CombineTrees (BinTree T1,BinTree T2)     //合并同样大小两颗二项树
{
   if(T1->Element > T2->Element )
	   return CombineTrees(T2,T1);
   T2->NextSibling = T1->LeftChild ;
   T1->LeftChild = T2;
   return T1;
}

BinQueue Merge(BinQueue H1,BinQueue H2)
{
   BinTree T1, T2,Carry = NULL;  //Carry记录上一次两个二项树合并的结果
   int i,j;
   if(H1->CurrentSize + H2->CurrentSize > Capacity)
	   cout << "Merge would exceed capacity" << endl;
   H1->CurrentSize += H2->CurrentSize ;
   for(i = 0, j = 1; j <= H1->CurrentSize; i++,j *= 2)   //i用来遍历两个二项队列,j用来结束循环
   {
      T1 = H1->TheTrees [i];
	  T2 = H2->TheTrees [i];

	  switch(!!T1 + 2 * !!T2 + 4 * !!Carry)  //!!运算符表示把T的空或者非空转换为0或者1
	  {
	  case 0:   //没有树
	  case 1:   //只有H1
		  break;
	  case 2:   //只有H2
		  H1->TheTrees [i] = T2;
		  H2->TheTrees [i] = NULL;
		  break;
	  case 4:   //只有Carry
		  H1->TheTrees [i] = Carry;
		  Carry = NULL;
		  break;
	  case 3:    //有H1和H2
		  Carry = CombineTrees(T1,T2);
		  H1->TheTrees [i] = H2->TheTrees [i] = NULL;
		  break;
	  case 5:   //H1和Carry
		  Carry = CombineTrees(T1,Carry);
		  H1->TheTrees [i] = NULL;
		  break;
	  case 6:   //H2和Carry
		  Carry = CombineTrees(T2,Carry);
		  H2->TheTrees [i] = NULL;
		  break;
	  case 7:   //3个树都有
		  H1->TheTrees [i] = Carry;
		  Carry = CombineTrees(T1,T2);
		  H2->TheTrees [i] = NULL;
		  break;
	  }
   }
   return H1;
}

void Insert(int x, BinQueue H)    //通过合并操作来完成,先对元素x建立一个二项队列,接着把这个队列和原来的队列合并
{
    BinQueue temp = Initialize();
    temp->CurrentSize  = 1;
    temp->TheTrees [0] = (BinTree)malloc(sizeof(struct BinNode));
    if (temp->TheTrees[0] == NULL)
        cout << "Empty binomial queue" << endl;
    temp->TheTrees[0]->Element  = x;
    temp->TheTrees[0]->LeftChild  = NULL;
    temp->TheTrees[0]->NextSibling  = NULL;
    Merge(H, temp);
    free(temp);
}  

bool IsEmpty(BinQueue H)
{
    if(H->CurrentSize == 0)
		return true;
	else
		return false;
}

int Find_Min (BinQueue H)
{
   int MinItem = Infinity;
   for(int i = 0;i < MaxTrees; i++)
   {
      if(H->TheTrees [i] && H->TheTrees [i]->Element < MinItem)
	  {
	      MinItem = H->TheTrees [i]->Element;
	  }
   }
   return MinItem;
}

int Delete (BinQueue H)   //删除最小值并返回最小值
{
   int i, j;
   int MinTree;    //最小的元素所在的二项树
   BinQueue DeletedQueue;
   Position DeletedTree,OldRoot;
   int MinItem;   //要返回的最小值

   if(IsEmpty(H))
   {
      cout << "Empty binomial queue" << endl;
	  return -Infinity;
   }

   //寻找最小值,只可能在根处
   MinItem = Infinity;
   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];
   OldRoot = DeletedTree;
   DeletedTree = DeletedTree->LeftChild;
   free(OldRoot);

   DeletedQueue = Initialize();
   DeletedQueue->CurrentSize = (1 << MinTree) - 1;  //此处为右移再-1
   for(j = MinTree - 1;j >= 0; j--)
   {
      DeletedQueue->TheTrees [j] = DeletedTree;
	  DeletedTree = DeletedTree->NextSibling ;
	  DeletedQueue->TheTrees [j]->NextSibling = NULL;
   }

   H->TheTrees [MinTree] = NULL;
   H->CurrentSize -= DeletedQueue->CurrentSize + 1;

   Merge(H,DeletedQueue);   //H为原来的二项队列删除具有最小元素的根节点的二项树后的二项队列,
                           //DeletedQueue为具有最小元素的根节点的二项树删除最小节点后剩余元素组成的二项队列
   return MinItem;    //返回最小值

}

int main ()
{
  BinQueue H = Initialize();
  Insert(13, H);
  Insert(23, H);
  Insert(24, H);
  /*Insert(51, H);
  Insert(65, H);
  Insert(12, H);
  Insert(14, H);
  Insert(24, H);
  Insert(21, H);
  Insert(65, H);
  Insert(16, H);
  Insert(26, H);
  Insert(18, H);*/

 // cout << H->CurrentSize <<endl;
  //cout << H->TheTrees [2]->Element << endl;
  cout << Find_Min (H)<< endl;
  cout << Delete(H) << endl;
  cout << Delete(H) << endl;
  cout << Delete(H) << endl;
  cout << Delete(H) << endl;

   return 0;
}

   例子中值得学习的地方很多,比如对合并时候几种情况的处理用switch语句分类实现,插入操作用合并操作实现等。

夜深了,,,

我在想什么

时间: 2024-08-26 07:36:17

数据结构--二项队列的思想与实现的相关文章

数据结构--二项队列分析及实现

一,介绍 什么是二项队列,为什么会用到二项队列? 与二叉堆一样,二项队列也是优先级队列的一种实现方式.在 数据结构--堆的实现之深入分析 的末尾 ,简单地比较了一下二叉堆与二项队列. 对于二项队列而言,它可以弥补二叉堆的不足:merge操作的时间复杂度为O(N).二项队列的merge操作的最坏时间复杂度为O(logN). 二,二项队列的基本操作及实现 在详细介绍二项的队列的基本操作之前,先了解下二项队列这种数据结构: 1)一个二项队列是若干棵树的集合.也就是说,二项队列不仅仅是一棵树,而是多棵树

转载:数据结构 二项队列

0)引论 左堆的合并,插入,删除最小的时间复杂度为O(logN).二项队列就是为了对这些结果进一步提高的一种数据结构.利用二项队列,这三种操作的最坏时间复杂度为O(logN),但是插入的平均时间复杂度为O(1). 1)二项队列 二项队列不是一棵树,它是一个森林,由一组堆序的树组成的深林,叫做二项队列. 二项队列有几个性质比较重要 (a) 每一颗树都是一个有约束的堆序树,叫做二项树 (b) 高度为k的第k个二项树Bk由一个根节点和B0, B1, .......B(k-1)构成 (c) 高度为k的二

二项队列———数据结构与算法分析第二版(C)

引论 左堆的合并,插入,删除最小的时间复杂度为O(logN).二项队列就是为了对这些结果进一步提高的一种数据结构.利用二项队列,这三种操作的最坏时间复杂度为O(logN),但是插入的平均时间复杂度为O(1) 二项队列 二项队列不是一棵树,它是一个森林,由一组堆序的树组成的深林,叫做二项队列. 二项队列有几个性质比较重要 (a) 每一颗树都是一个有约束的堆序树,叫做二项树 (b) 高度为k的第k个二项树Bk由一个根节点和B0, B1, .......B(k-1)构成 (c) 高度为k的二项树的结点

优先队列——二项队列(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

二项队列

二项队列是 堆序 的集合,也叫 森林.其中每一种形式都有约束. 二项树Bk由一个带有儿子的B0,B1,B2...组成,高度为k的二项树 恰好有2^k个结点.每一种高度只能出现一次...因此,只有1,2,4,8...等结点数目的二项树 deleteMin操作需要快速的找出跟的所有子树的能力,因此需要一般树的表示方法: 每个结点的儿子都在一个链表中,而且每个结点都有一个指向它的第一个儿子的指针. 二项树的每一个结点包括:数据,第一个儿子,以及右兄弟 下面是二项队列类构架及结点定义: 1 templa

二项队列的查找插入合并操作

源码例如以下: /* <span style="color:#ff0000;">一棵二次幂堆</span>是一棵左有序的堆,由右子树为空左子树为全然二叉树构成的根组成 <span style="color:#ff0000;">二项队列</span>:是二次幂堆的一个集合. 当中不存在相等大小的堆.其结构由队列节点数目确定 相应整数的二进制表示. */ #include <stdlib.h> #include

优先队列(堆)&#183;二项队列

目录 一. 定义 二. 结构 三. 操作 3.1. 合并 3.1. 删除最小值(deleteMin) 四. 二项队列的实现 代码地址 一. 定义 ? 我们知道,左式堆每次操作的时间界是\(O(logN)\).二项队列支持合并.插入.删除最小值,每次插入的平均时间为常数时间,而最坏时间是\(O(logN)\). ? 二项队列: 不是一棵堆序的树,而是堆序的树的集合,成为森林. 森林的每棵树都是二项树(binomial tree). 每个高度上至多存在一棵二项树. 二. 结构 ? 结构图解: ? 高

数据结构——二项堆

二项树的介绍 二项树的定义 二项堆是二项树的集合.在了解二项堆之前,先对二项树进行介绍. 二项树是一种递归定义的有序树.它的递归定义如下:(01) 二项树B0只有一个结点:(02) 二项树Bk由两棵二项树B(k-1)组成的,其中一棵树是另一棵树根的最左孩子.如下图所示: 上图的B0.B1.B2.B3.B4都是二项树.对比前面提到的二项树的定义:B0只有一个节点,B1由两个B0所组成,B2由两个B1所组成,B3由两个B2所组成,B4由两个B3所组成:而且,当两颗相同的二项树组成另一棵树时,其中一棵

JavaScript数据结构和算法----队列

前言 队列和栈很像,只是用了不同的原则.队列是遵循先进先出(FIFO)原则的一组有序的的项,队列在尾部添加新元素,从顶部移除元素.最新添加的元素必须必须排队在队列的,末尾.可以想象食堂排队买饭的样子. 一.创建队列 1.创建一种数据结构来保存队列里面的数据,这里选择数组 2.声明一些栈的方法 enqueue(element(s)) : 添加一个或一些元素到队列的末尾 dequeue() : 移除队列第一个的元素(就是排队在最前面的),同时返回被移除的元素. front() : 返回队列第一个的元