参考算法导论以及这个博主的代码:
https://blog.csdn.net/chenhanzhun/article/details/21443555
完整C语言实现如下
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#define MAX 0x3f3f3f3f //表示正无穷
typedef int Type;
typedef struct _BNode *BinomialNode;
typedef struct _BNode //结点的结构体
{
Type key;
int degree;
BinomialNode child;
BinomialNode parent;
BinomialNode sibling;
}Node;
typedef struct Heap *BinomialHeap;
typedef struct Heap //每个二项堆的堆顶连成一个链表
{
BinomialNode head;
}Binheap;
//函数声明
void SWAP(BinomialNode x, BinomialNode y);
BinomialHeap CREATE();
BinomialNode MINIMUM(BinomialHeap H);
void LINK(BinomialNode y, BinomialNode z);
BinomialNode MERGE(BinomialHeap H1, BinomialHeap H2);
BinomialHeap UNION(BinomialHeap H1, BinomialHeap H2);
BinomialHeap INSERT(BinomialHeap H, BinomialNode x);
void EXTRACT(BinomialHeap H);
void DECREASE(BinomialHeap H, BinomialNode x, int k);
void DELETE(BinomialHeap H, BinomialNode x);
void PRINT(BinomialNode H);
void SWAP(BinomialNode x, BinomialNode y) //交换两个结点
{
BinomialNode t;
t = x;
x = y;
y = t;
}
void swap(int k1, int k2)
{
int t;
t = k1;
k1 = k2;
k2 = t;
}
BinomialHeap CREATE() //创建一个二项堆
{
BinomialHeap H = (BinomialHeap)malloc(sizeof(Binheap)); //分配一个对象H,头指针为空
//H = NULL;
H->head = NULL;
return H;
}
BinomialNode CREATE_NODE(Type k) //创建一个结点
{
BinomialNode x = (BinomialNode)malloc(sizeof(Node));
x->key = k;
x->parent = NULL;
x->child = NULL;
x->degree = 0;
x->sibling = NULL;
return x;
}
BinomialNode MINIMUM(BinomialHeap H) //最小的结点
{
BinomialNode y = NULL;
BinomialNode x = H->head;
int min = MAX;
while (x != NULL)
{
if (x->key < min)
{
min = x->key;
y = x;
}
x = x->sibling;
}
return y;
}
void LINK(BinomialNode y, BinomialNode z) //连接两个结点
{
y->parent = z;
y->sibling = z->child;
z->child = y;
z->degree = z->degree + 1;
}
BinomialNode MERGE(BinomialHeap H1, BinomialHeap H2) //将H1、H2的根表合并成一个度数单调递增的链表
{
BinomialHeap H = CREATE();
BinomialNode x = H1->head;
BinomialNode y = H2->head;
BinomialNode z = NULL;
if (x == NULL) //找到head
return y;
if (y == NULL)
return x;
if (x->degree < y->degree)
{
H->head = x;
x = x->sibling;
}
else
{
H->head = y;
y = y->sibling;
}
z = H->head;
while (x != NULL && y != NULL) //在H1,H2两个堆中按度递增寻找合适的结点串起来
{
if (x->degree < y->degree)
{
z->sibling = x;
x = x->sibling;
}
else
{
z->sibling = y;
y = y->sibling;
}
z = z->sibling;
}
while (x != NULL) //剩下的逐一复制到z里面
{
z->sibling = x;
x = x->sibling;
z = z->sibling;
}
while (y != NULL)
{
z->sibling = y;
y = y->sibling;
z = z->sibling;
}
return H->head;
}
BinomialHeap UNION(BinomialHeap H1, BinomialHeap H2) //把两个堆连起来
{
BinomialHeap H = CREATE();
H->head = MERGE(H1, H2);
if (H->head == NULL)
{
// printf("这是一个空");
return H;
}
BinomialNode prev_x = NULL;
BinomialNode x = H->head;
BinomialNode next_x = x->sibling;
while (next_x != NULL) //四种情况分类讨论
{
if ((next_x->degree != x->degree )||
(next_x->sibling != NULL && next_x->sibling->degree == x->degree))
{
prev_x = x;
x = next_x;
}
else if (x->key < next_x->key)
{
x->sibling = next_x->sibling;
LINK(next_x, x);
}
else
{
if (prev_x == NULL)
H->head = next_x;
else
{
prev_x->sibling = next_x;
}
LINK(x, next_x);
x = next_x;
}
next_x = x->sibling;
}
return H;
}
BinomialHeap INSERT(BinomialHeap H, BinomialNode x) //将x结点插入堆H
{
BinomialHeap HX = CREATE();
HX->head = x;
HX = UNION(H, HX);
return HX;
}
void PRINT(BinomialNode HNode) //打印二项堆,结果是从第一个数字开始一个完整的括号为一颗二项树
{
if (HNode == NULL)
return;
BinomialNode p = HNode;
while (p != NULL)
{
printf("(");
printf("%d", p->key);
if (p->child != NULL)
{
PRINT(p->child);
}
printf(")");
p = p->sibling;
}
}
void EXTRACT(BinomialHeap H)
{
BinomialNode x=NULL, prev_x=NULL,h,prev_h=NULL; //x store the min
int min=MAX;
h = H->head;
while (h != NULL)
{
if (h->key < min)
{
min = h->key;
prev_x = prev_h;
x = h;
}
prev_h = h;
h = h->sibling;
}
if (prev_x == NULL) //delete x
H->head = x->sibling;
else
{
prev_x->sibling = x->sibling;
}
BinomialNode ch = x->child;
BinomialHeap new_heap = CREATE();
BinomialNode temp=NULL;
while (ch != NULL) //use temp and head to realise a convert
{
temp = ch;
ch = ch->sibling;
temp->sibling = H->head;
H->head = temp;
temp->parent = NULL;
}
UNION(new_heap, H);
}
BinomialNode SEARCH(BinomialNode node, int k) //递归查找结点
{
BinomialNode x = node;
BinomialNode p = NULL;
if (x->key == k) //查找到了返回结点
{
p = x;
return p;
}
if (x->child != NULL && p == NULL) //向下查找
{
p = SEARCH(x->child, k);
}
if (x->sibling != NULL && p == NULL) //向右查找
{
p = SEARCH(x->sibling, k);
}
return p;
}
void DELETE(BinomialHeap H, BinomialNode x)
{
DECREASE(H, x, -MAX); //先变成负无穷放到最上面去
EXTRACT(H); //在把最小的extract出去
}
void DECREASE(BinomialHeap H, BinomialNode x, int k)
{
BinomialNode y = NULL, z= NULL;
int temp;
if (k > x->key)
return;
x->key = k;
y = x;
z = y->parent;
while (z != NULL && y->key < z->key)
{
// swap((x->key),(y->key)); //根本就没有交换
temp = y->key;
y->key = z->key;
z->key = temp;
y = z;
z = y->parent;
}
}
int main()
{
int size1,size2, k1,k2;
BinomialHeap heap=CREATE();
BinomialHeap new_heap = CREATE();
BinomialHeap H=CREATE();
BinomialNode node1,node2;
printf("enter the size of heap:\n");
scanf_s("%d", &size1);
printf("enter all of numbers\n");
for (int i = 0; i < size1; i++) //构建第一个二项堆
{
scanf_s("%d", &k1);
node1=CREATE_NODE(k1);
heap = INSERT(heap,node1);
}
PRINT(heap->head);
printf("\nenter a new heap,the size is :\n"); //构建第二个二项堆
scanf_s("%d", &size2);
printf("enter all of numbers\n");
for (int i = 0; i < size2; i++)
{
scanf_s("%d", &k2);
node2 = CREATE_NODE(k2);
new_heap = INSERT(new_heap, node2);
}
PRINT(new_heap->head);
printf("\nafter union two heaps ,the result is:\n"); //检验合并
H = UNION(heap, new_heap);
PRINT(H->head);
printf("\nthe minimum is :\n");
node1 = MINIMUM(H);
printf("%d", node1->key);
printf("\nafter extract min is:\n "); //检验extract min
EXTRACT(H);
PRINT(H->head);
printf("\nwhich number do you want to decrease :\n"); //检验decrease
scanf_s("%d", &k1);
node1 = SEARCH(H->head, k1);
printf("decrease it to :\n");
scanf_s("%d", &k2);
DECREASE(H,node1,k2);
printf(" result is:\n");
PRINT(H->head);
printf("\nwhich number do you want to delete:\n");
scanf_s("%d", &k1);
node1 = SEARCH(H->head, k1);
DELETE(H, node1);
printf("result is:\n");
PRINT(H->head);
return 0;
}
说一下输出这是怎么看的:
是递归输出的,从左孩子开始,然后是左孩子的右兄弟,一个完整的括号为一颗二项树具体来说就是:
(2(3))(4(8(9)))(6))
B1 B2
2-------------4
| /
3 8 6
/
9
需要注意的地方:
结构体的定义,二项堆定义了两个结构体,一个是结点的,一个是根的链表的,都是定义一个变量一个指针,而且用到typedef的时候必须要先更名,结构体里面才能用更名后的名字,结构体这里一定要弄好,不然到时候编译的时候会有几十行的变量类型对应不上,结构体,typedef,mallloc,结构体指针,结构体的参数列表 我还得总结一下,自己写老是错。
重点就是指针,得有一个动态的思维和对应关系现在指针在哪里,指针怎么动的,一定一定要判断指针为空。出来一个黑框还没输出或输入完就输不动或是然后不动了或者直接按任意键继续了很有可能就是指针的问题,指向不正确,找不到位置了,指针空了等。
对于树的输出,要习惯用递归,很简洁很方便。
(搞了两天,debug了接近一天,终于搞出来了…事实证明,稍微长一些的代码断点调试是真的好用)