最小二项堆

最小二项堆:



1. 节点的关键字(key)大于或等于父节点的关键字.

2. degree表示子女的个数

3. slibing指向紧右的兄弟结点,最右节点的slibing为NIL.

4. 二项堆的根节点组织成一个链表(有slibing连接): 根表

5. parent指向父节点,根节点的parent为NIL

6.child指向左边第一个子节点

7. head指向度数(degree)最小的节点,根表的度数严格递增,不能有相同degree的节点父节点

8.






#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define  INT_MAX    0x7FFFFFFF 
#define  INT_MIN    (-INT_MAX - 1)

//#define  NULL   0
#define  false  0
#define  true   1


typedef struct BinomialHeapNode
{
  int                    key;
  int                    degree; //本节点子女的个数
  struct BinomialHeapNode     *parent;  /*指向父节点*/
  struct BinomialHeapNode     *child;   /*指向子节点*/
  /*指向紧右的兄第节点,右边紧挨着的兄弟节点;如果为根节点,则指向下一个根节点*/
  struct BinomialHeapNode     *sibling;  
  void*                 satellite;     /*the satellite data keep in the node*/
}BinomialHeapNode;



typedef BinomialHeapNode    *BinomialHeap;
typedef BinomialHeapNode    *BinoNode_point;


BinomialHeapNode* MakeBinomialHeap()
{    
     BinomialHeapNode*  BinoHeap = NULL;

     BinoHeap = (BinomialHeapNode*)malloc(sizeof(BinomialHeapNode));
     if(NULL == BinoHeap)
     {
          printf("malloc failed %s, %d \n", __FILE__, __LINE__);

          return NULL;
     }

     BinoHeap->child = NULL;
     BinoHeap->degree = 0;
     BinoHeap->parent = NULL;
     BinoHeap->sibling = NULL;
     BinoHeap->satellite = NULL;
     
     return BinoHeap;

     
}

/************************************************************************
 * BinomialHeapMinimum
 *
 *  get the node of  least key in the heap;

    go through the root list of Binomial Heap and find the least key 

 * @heap   the head of heap
 *
 * return: the node of the least key in the heap
 ************************************************************************/
BinomialHeapNode* BinomialHeapMinimum(BinomialHeap heap)
{
    BinoNode_point x = heap, y = NULL;
    int      min = INT_MAX;

    while(NULL != x)
    {
         /*go through the root list of Binomial Heap and find the least key*/
        if(x->key < min)
        {
            min = x->key;
            y = x;
        }

        x = x->sibling;
        
    }

    return y;

    
}

/*****************************************************************************
*BinomialLink
*
*Link two Binomial heap with same degree, the the second will be the father 
 after the link, 

 note: the input parameter should not be NULL;
*
* @heap1  the heap1 will be the child of heap2 after the link
* @heap2  the heap2 will be the parent of heap1 aftre the link 
*
*****************************************************************************/
void BinomialLink(BinomialHeap heap1, BinomialHeap heap2)
{

     heap1->parent = heap2;         /*set heap2 as the parent of heap1 */
     heap1->sibling = heap2->child; /*set the heap2's child as heap1's sibling*/
     heap2->child = heap1;          /*set the heap1 as heap2 child*/
     heap2->degree++;

     return;
}

/******************************************************************************
*BinomialHeapMerge

  Merge the root lists of two Heap in the order of degree of the root node.
*@H1 the first Heap which is merged in the heap
*@H2 the second heap which is merged in the heap


*return the new heap the H1 and H2 after been merged.
*****************************************************************************/
BinomialHeap BinomialHeapMerge(BinomialHeap H1, BinomialHeap H2)
{

    BinomialHeap heap = NULL;
    BinoNode_point      firstNode = NULL, secondNode = NULL, pre_H3 = NULL, H3 = NULL;  

    if((H1 != NULL) && (H2 != NULL))
    {
         firstNode = H1;
         secondNode = H2;

         while((firstNode != NULL) && (secondNode != NULL))
         {
             //那个node的degree小就将H3指向那个node
             if(firstNode->degree <= secondNode->degree)
             {
                 H3 = firstNode;
                 firstNode = firstNode->sibling;
                 
             }
             else
             {
                 H3 = secondNode;
                 secondNode = secondNode->sibling;
                 
             }

             if(NULL == pre_H3)
             {
                 pre_H3 = H3;
                 heap = H3;
             }
             else
             {
                 pre_H3->sibling = H3; //将小的node插入到已排好序的链表
                 pre_H3 = H3; //将H3暂时保存到pre_H3用于后续将sibling连到H3
             }

             //将H3的sibling连接到下一个非空的node(除非两个都是NULL)
             if(firstNode != NULL)
             {
                 H3->sibling = firstNode;  
             }
             else
             {
                 H3->sibling = secondNode;
             }
 
         }
    
    }
    else if(H1 != NULL)
    {
        heap = H1;
    }
    else if(H2 != NULL) 
    {
        heap = H2;
    }
    else
    {
        heap = NULL;
    }

    return heap;
}

/******************************************************************************
*BinomialHeapUnion

  There are two stage in BinomialHeapUnion: 
  1.  Call BinomialHeapMerge to merge the root link of two heap in order of 
      the degree of root nodes.
  2.  Link the roots which have same degrees until all roots' degrees are different.
  
*@H1 the first Heap which is united in the heap
*@H2 the second heap which is united in the heap


*return the new heap the H1 and H2 after been united.
*****************************************************************************/
BinomialHeap BinomialHeapUnion(BinomialHeap H1, BinomialHeap H2)
{
    BinomialHeap heap = NULL;
    BinoNode_point      x = NULL, pre_x = NULL, next_x = NULL;

    heap = BinomialHeapMerge(H1, H2); /*Merge two root links*/

    if(NULL == heap)
        return NULL;


    x = heap;
    next_x = x->sibling;

    while(NULL != next_x)
    {
        if((x->degree != next_x->degree) ||  /*case 1: 两个连续的node degree不同,跳过到下一个*/
             ((next_x->sibling != NULL)&&(x->degree == next_x->sibling->degree)))/*case2:上个连续的node degree都相同, 跳过后到了下次循环时会进入到case3 or case4*/
        {
            pre_x = x;
            x = next_x;
        }
        else if(x->key <= next_x->key) //case 3. The key of x is smaller, link next_x to x, so the sibling of x will link to the sibling of next_x
        {
            x->sibling = next_x->sibling;
            BinomialLink(next_x, x);
        }
        else //case 4. 
        {

            if(NULL == pre_x) /*first loop of key of x is bigger than next_x*/
            {
                heap = next_x;
            }
            else
            {
                pre_x->sibling = next_x;
            }

            BinomialLink(x, next_x);
            x = next_x;
        }

        next_x = x->sibling;
    }

    return heap;
    
}


/******************************************************************************
*BinomialHeapInsert

  Inset a Node in to the heap  
  
*@H the Heap which the node will be inserted
*@node the Node which is inserted in the heap


*return the new heap the after the node had been inserted
*****************************************************************************/
BinomialHeap BinomialHeapInsert(BinomialHeap H, BinomialHeapNode* node)
{
    BinomialHeap  heap, heapret = NULL;

    if(NULL == node)
    {
         printf("Input parameter node is null %s, %d \n", __FILE__, __LINE__);
         return H;
    }
    node->parent = NULL;
    node->child = NULL;
    node->sibling = NULL;
    node->degree = 0;

    heap = node;

    heapret = BinomialHeapUnion(H, heap);

    return heapret;
    
}

/******************************************************************************
*BinomialHeapExtractMin

  Extract the Min key Node from Heap  
  
*@H [in/out]the  Heap which the node will be extracted.
*


*return the min key node extracted from the heap
*****************************************************************************/
BinomialHeapNode* BinomialHeapExtractMin(BinomialHeap* H)
{
    BinoNode_point    x = *H, y = NULL, pre_y = NULL, p;
    BinomialHeap H2 = NULL;
    int         minkey;

    minkey = INT_MAX;

    if(NULL == *H)
    {
        printf("Input parameter heap is null %s, %d \n", __FILE__, __LINE__); 

        return NULL;
    }

    /*get the min key node and set it to y*/
    while(x != NULL)
    {
        if(x->key < minkey)
        {
            minkey = x->key;
            pre_y = y;
            y = x;
        }

        x = x->sibling;
    }

    if (y == NULL)
    {
        return NULL;
    }
    
    if(NULL == pre_y) /*if the min key node is the first node of the list */
    {
        *H = (*H)->sibling;  /*remove y from the list*/
    }
    else
    {
        pre_y->sibling = y->sibling;  /*remove y from the list*/
    }

    x = y->child;

    /*reverse the order of the linked list of the children of the min key node*/
    while(NULL != x)
    {
        p = x;
        x = x->sibling;
        p->sibling = H2;
        H2 = p;
        p->parent = NULL;
        
    }
    
    *H = BinomialHeapUnion(*H, H2);

    return y;
    
}

/******************************************************************************
BinomialHeapDecreaseKey

decrease the key of node x to the input newkey

@H Heap which include the node x, the x should in the heap
@x The node x which key value will be decrease to newkey
@newkey the newkey value of x after decrease

return: if success, return true, else return false

******************************************************************************/
int  BinomialHeapDecreaseKey(BinomialHeap H, BinomialHeapNode* x, int newkey)
{
    BinoNode_point  y, z;
    int temp;
    void* tempsatellite;
    
    if(newkey > x->key)
    {
       printf("new key(%d) is greaer than current key %s, %d \n", newkey, __FILE__, __LINE__); 

       return false;
    }

    x->key = newkey;

    y = x;
    z = y->parent;

    while((NULL != z) && (z->key > y->key))
    {
        temp = y->key;
        y->key = z->key;
        z->key = temp;

        tempsatellite = y->satellite;
        y->satellite = z->satellite;
        z->satellite = tempsatellite;

        y = z;
        z = y->parent;
        
    }

    return true;
    
}

/******************************************************************************
BinomialHeapDelete

decrease the key of node x to the input newkey

@H Heap which include the node x, the x should in the heap
@x The node x which   will be deleted

return: the deleted node

******************************************************************************/
BinomialHeapNode* BinomialHeapDelete(BinomialHeap H,  BinomialHeapNode* x)
{
    BinomialHeapDecreaseKey(H, x, INT_MIN);

    return BinomialHeapExtractMin(&H);

}


/******************************************************************************
BinomialHeapFindByKey

search the node whose key value is equal to key

@H Heap which want to search
@key The key value of the node which want to search

return: if finded, return the node, else return NULL

******************************************************************************/
BinomialHeapNode* BinomialHeapFindByKey(BinomialHeap H, int key)
{

    BinoNode_point  p = NULL, x = NULL;

    p = H;

    while(NULL != p)
    {

        if(key == p->key)
        {
          return p;
        }

        if(NULL !=(x = BinomialHeapFindByKey(p->child, key)))
        {
            return x;
        }
        
        /*The searching of pre root finish, search the next root*/

        p = p->sibling;
    }
    
    return NULL;
    
}

/******************************************************************************
BinomialHeapDeleteByKey

decrease the key of node x to the input newkey

@H  The heap want to be delete the node whose key value equal the key 
@key the key is used to indentify the the delete node

return: the deleted node, but the key had been updated

******************************************************************************/
BinomialHeapNode* BinomialHeapDeleteByKey(BinomialHeap* H,  int key)
{
    BinoNode_point x = NULL;

    x = BinomialHeapFindByKey(*H, key);

    if(NULL == x)
    {
         printf("The key(%d) is not in the heap %s, %d \n", key, __FILE__, __LINE__); 

         return *H;
    }

    BinomialHeapDecreaseKey(*H, x, INT_MIN);

    return BinomialHeapExtractMin(H);

}



void BinomialHeapPrint(BinomialHeap H)
{
     BinoNode_point  p = NULL;
     
     if(NULL == H)
     {
         printf("The heap is NULL %s, %d \n", __FILE__, __LINE__); 
         return;
     }

     p = H;

     while(NULL != p)
     {

         printf("(");
         printf("%d ", p->key);

         if(NULL != p->child)
         {
              BinomialHeapPrint(p->child);
         }

         printf(") ");

         p = p->sibling;
       
     }

     return;
     
}



//用数组内的值建堆
BinomialHeap MakeBinHeapWithArray(int keys[], int n)
{
    BinomialHeap heap = NULL, newHeap = NULL;
    int i;

    for ( i = 0; i < n; i++)
    {
        newHeap = (BinomialHeap) malloc(sizeof(BinomialHeapNode));

        if (newHeap == NULL)
        {
            printf("malloc failed %s, %d \n", __FILE__, __LINE__);
            exit(1);
        }

        memset(newHeap, 0, sizeof(BinomialHeapNode));
        newHeap->key = keys[i];

        if (NULL == heap)
        {
            heap = newHeap;
        }
        else
        {
            heap = BinomialHeapUnion(heap, newHeap);
            newHeap = NULL;
        }
    }

    return heap;
}



int kp1[8] = {12,
              7, 25,
              15, 28, 33, 41
             };

int kp2[20] = {18,
               3, 37,
               6, 8, 29, 10, 44, 30, 23, 2, 48, 31, 17, 45, 32, 24, 50, 55
              };

int kp4[23] = {37, 41,
               10, 28, 13, 77,
               1, 6, 16, 12, 25, 8, 14, 29, 26, 23, 18, 11, 17, 38, 42, 27
              };

int main()
{
    BinomialHeap H1 = NULL;
    H1 = MakeBinHeapWithArray(kp1, 7);
    printf("The first Binomial Heap H1\n");
    BinomialHeapPrint(H1);

    BinomialHeap H2 = NULL;
    H2 = MakeBinHeapWithArray(kp2, 19);
    printf("The Second Binomial Heap H2\n");
    BinomialHeapPrint(H2);

    BinomialHeap H3 = NULL;
    H3 = BinomialHeapUnion(H1, H2);
    printf("\n\n The Union Heap H3 after United H1, H2 \n");
    BinomialHeapPrint(H3);

    BinomialHeap H4 = NULL;
    H4 = MakeBinHeapWithArray(kp4, 22);
    printf("\n\n The H4 used for test extract and delet node from H4\n");
    BinomialHeapPrint(H4);

    BinomialHeap extractNode = BinomialHeapExtractMin(&H4);

    if (extractNode != NULL)
    {
        printf("\n\n after extract the min from H4  %d \n", extractNode->key);
        BinomialHeapPrint(H4);

        free(extractNode);
    }

    

    extractNode = BinomialHeapExtractMin(&H4);

    if (extractNode != NULL)
    {
        printf("\n\n after extract the minum from H4 %d \n", extractNode->key);
        BinomialHeapPrint(H4);
        free(extractNode);
    }

    extractNode = BinomialHeapExtractMin(&H4);
    

    if (extractNode != NULL)
    {
        printf("\n\n after extract the minum from H4 %d \n", extractNode->key);
        BinomialHeapPrint(H4);
        free(extractNode);
    }
    

    extractNode = BinomialHeapDeleteByKey(&H4, 12);
    if(NULL != extractNode)
    {
        extractNode->key = 12;
        printf("\n\n after delete %d from H4 \n", extractNode->key);
        BinomialHeapPrint(H4);
        free(extractNode);
        
    }

    printf("\n");
    return 0;
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值