斐波那契堆

/****************************
说明:
代码中Fibonacci Heap 用变量heap表示
结点通常用x,y等表示
****************************/

#include<iostream>
#include<cstdio>
#include<stdlib.h>
#include<string.h>
#include<cmath>
#include<climits>
using namespace std;

//斐波那契结点ADT
struct FibonacciHeapNode
{
    int key;       //结点
    int degree;    //度
    FibonacciHeapNode * left;  //左兄弟
    FibonacciHeapNode * right; //右兄弟
    FibonacciHeapNode * parent; //父结点
    FibonacciHeapNode * child;  //第一个孩子结点
    bool marked;           //是否被删除第1个孩子,如果孩子已经被删除了一个,则标记为true,再进行剪枝时自己也要剪

};                         /**********************************
                           总大小本应是24+1=28;
                           然而编译出来是28,因为存在内存对齐
                           ***********************************/


typedef FibonacciHeapNode FibNode;

//斐波那契堆ADT
struct FibonacciHeap
{
    int keyNum;   //堆中结点个数
    FibonacciHeapNode * min;//最小堆,根结点
    int maxNumOfDegree;   //最大度
    FibonacciHeapNode ** cons;//指向最大度的内存区域
};

typedef FibonacciHeap FibHeap;

/*****************函数申明*************************/
//将x从双链表移除
inline void FibNodeRemove(FibNode * x);

//将x堆结点加入y结点之前(循环链表中)
void FibNodeAdd(FibNode * x, FibNode * y);

//初始化一个空的Fibonacci Heap
FibHeap * FibHeapMake() ;

//初始化结点x
FibNode * FibHeapNodeMake();

//堆结点x插入fibonacci heap中
void FibHeapInsert(FibHeap * heap, FibNode * x);

//将数组内的值插入Fibonacci Heap
void FibHeapInsertKeys(FibHeap * heap, int keys[], int keyNum);

//将值插入Fibonacci Heap
static void FibHeapInsertKey(FibHeap * heap, int key);

//抽取最小结点
FibNode * FibHeapExtractMin(FibHeap * heap);

//合并左右相同度数的二项树
void FibHeapConsolidate(FibHeap * heap);

//将x根结点链接到y根结点
void FibHeapLink(FibHeap * heap, FibNode * x, FibNode *y);

//开辟FibHeapConsolidate函数哈希所用空间
static void FibHeapConsMake(FibHeap * heap);

//将堆的最小结点移出,并指向其有兄弟
static FibNode *FibHeapMinRemove(FibHeap * heap);

//减小一个关键字
void FibHeapDecrease(FibHeap * heap, FibNode * x, int key);

//切断x与父节点y之间的链接,使x成为一个根
static void FibHeapCut(FibHeap * heap, FibNode * x, FibNode * y);

//级联剪切
static void FibHeapCascadingCut(FibHeap * heap, FibNode * y);

//修改度数
void renewDegree(FibNode * parent, int degree);

//删除结点
void FibHeapDelete(FibHeap * heap, FibNode * x);

//堆内搜索关键字
FibNode * FibHeapSearch(FibHeap * heap, int key);

//被FibHeapSearch调用
static FibNode * FibNodeSearch(FibNode * x, int key);

//销毁堆
void FibHeapDestory(FibHeap * heap);

//被FibHeapDestory调用
static void FibNodeDestory(FibNode * x);

//输出打印堆
static void FibHeapPrint(FibHeap * heap);

//被FibHeapPrint调用
static void FibNodePrint(FibNode * x);
/************************************************/





//将x从双链表移除
inline void FibNodeRemove(FibNode * x)
{
    x->left->right = x->right;
    x->right->left = x->left;
}

/*
将x堆结点加入y结点之前(循环链表中)
    a …… y
    a …… x …… y
    亦即插入到y的紧邻左边
*/
inline void FibNodeAdd(FibNode * x, FibNode * y)
{
    x->left = y->left;
    y->left->right = x;
    x->right = y;
    y->left = x;
}

//初始化一个空的Fibonacci Heap
FibHeap * FibHeapMake()
{
    FibHeap *heap=NULL;
    heap=(FibHeap*)malloc(sizeof(FibHeap));
    if(NULL == heap)
    {
        puts("out of space");
        exit(1);
    }
    memset(heap,0,sizeof(FibHeap));
    return heap;
}

//初始化结点x
FibNode * FibHeapNodeMake()
{
    FibNode *node=NULL;
    node=(FibNode*)malloc(sizeof(FibNode));
    if(NULL == node)
    {
        puts("out of space!");
        exit(1);
    }
    memset(node,0,sizeof(FibNode));
    node->left = node->right = node;
    return node;
}

//堆结点x插入fibonacci heap中
void FibHeapInsert(FibHeap * heap, FibNode * x)
{
    if (0 == heap->keyNum)
    {
        heap->min = x;
    }
    else
    {
        FibNodeAdd(x, heap->min);
        x->parent = NULL;
        if (x->key < heap->min->key)
        {
            heap->min = x;
        }
    }
    heap->keyNum++;
}

//将数组内的值插入Fibonacci Heap
void FibHeapInsertKeys(FibHeap * heap, int keys[], int keyNum)
{
    for (int i = 0; i < keyNum; i++)
    {
        FibHeapInsertKey(heap, keys[i]);
    }
}

//将值插入Fibonacci Heap
static void FibHeapInsertKey(FibHeap * heap, int key)
{
    FibNode * x = NULL;
    x = FibHeapNodeMake();
    x->key = key;           //初始化插入结点
    FibHeapInsert(heap, x); //再将插入结点撤入到堆中,默认插入到最小结点的紧邻左边
}

//抽取最小结点
FibNode * FibHeapExtractMin(FibHeap * heap)
{
    FibNode * x = NULL, * z = heap->min;
    if (z != NULL)
    {

                                       //删除z的每一个孩子
        while (NULL != z->child)
        {
            x = z->child;
            FibNodeRemove(x);
            if (x->right == x)         // x已经没有兄弟了
            {
                z->child = NULL;
            }
            else
            {
                z->child = x->right;  //x还有兄弟,将z->child指向它的兄弟
            }
            FibNodeAdd(x, z);         //将z的所有孩子插入到z自己的左边
            x->parent = NULL;         //根结点链表无双亲
        }

        FibNodeRemove(z);             //z的孩子已经移完了,z删除
        if (z->right == z)
        {
            heap->min = NULL;
        }
        else
        {
            heap->min = z->right;      //暂时指定
            FibHeapConsolidate(heap);  //将堆整理好
        }
        heap->keyNum--;
    }
    return z;
}

//合并左右相同度数的二项树
void FibHeapConsolidate(FibHeap * heap)
{
    int D, d;
    FibNode * w = heap->min,
            * x = NULL,
            * y = NULL;

    FibHeapConsMake(heap);            //开辟哈希所用空间,即heap->cons[][]
    D = heap->maxNumOfDegree + 1;
    for (int i = 0; i < D; i++)
    {
        heap->cons[i] = NULL;
    }

    //合并相同度的根节点,使每个度数的二项树唯一
    while (NULL != heap->min)
    {
        x = FibHeapMinRemove(heap);    //f4返回key最小的结点
        d = x->degree;                 //此最小结点的度
        while (NULL != heap->cons[d])  //此位置已存入结点,代表两结点度相同,进行合并
        {
            y = heap->cons[d];
            if (x->key > y->key)
            {
                swap(x, y);
            }
            FibHeapLink(heap, y, x);  //保证y大,x小
            heap->cons[d] = NULL;
            d++;
        }
        heap->cons[d] = x;           //heap->cons[]存放的是结点
    }


    heap->min = NULL;//原有根表清除

    //将heap->cons中结点都重新加到根表中,且找出最小根
    for (int i = 0; i < D; i++)
    {
        if (heap->cons[i] != NULL)
        {
            if (NULL == heap->min)
            {
                heap->min = heap->cons[i];
            }
            else
            {
                FibNodeAdd(*(heap->cons + i), heap->min);
                if ((*(heap->cons + i))->key < heap->min->key)
                {
                    heap->min = *(heap->cons + i);
                }//if(<)
            }//if-else(==)
        }//if(!=)
    }//for(i)
}

//将x根结点链接到y根结点
void FibHeapLink(FibHeap * heap, FibNode * x, FibNode *y)
{
    FibNodeRemove(x);
    if (NULL == y->child)
    {
        y->child = x;
    }
    else
    {
        FibNodeAdd(x, y->child);
    }
    x->parent = y;
    y->degree++;
    x->marked = false;
}

//开辟FibHeapConsolidate函数哈希所用空间
static void FibHeapConsMake(FibHeap * heap)
{
    int old = heap->maxNumOfDegree;
    heap->maxNumOfDegree = int(log(heap->keyNum * 1.0) / log(2.0)) + 1;
    if (old < heap->maxNumOfDegree)
    {
        //因为度为heap->maxNumOfDegree可能被合并,所以要maxNumOfDegree + 1
        heap->cons = (FibNode **) realloc(heap->cons,
                                          sizeof(FibHeap *) * (heap->maxNumOfDegree + 1));
        if (NULL == heap->cons)
        {
            puts("Out of Space!");
            exit(1);
        }
    }
}

//将堆的最小结点移出,并指向其右兄弟
static FibNode *FibHeapMinRemove(FibHeap * heap)
{
    FibNode *minx = heap->min;
    if (heap->min == minx->right)
    {
        heap->min = NULL;
    }
    else
    {
        FibNodeRemove(minx);
        heap->min = minx->right;
    }
    minx->left = minx->right = minx;
    return minx;
}

//减小一个关键字
void FibHeapDecrease(FibHeap * heap, FibNode * x, int key)
{
    FibNode * y = x->parent;
    if (x->key < key)
    {
        puts("new key is greater than current key!");
        exit(1);
    }
    x->key = key;

    if (NULL != y && x->key < y->key)
    {
        //破坏了最小堆性质,需要进行级联剪切操作
        FibHeapCut(heap, x, y);
        FibHeapCascadingCut(heap, y);
    }
    if (x->key < heap->min->key)
    {
        heap->min = x;
    }
}

//切断x与父节点y之间的链接,使x成为一个根
static void FibHeapCut(FibHeap * heap, FibNode * x, FibNode * y)
{
    FibNodeRemove(x);
    renewDegree(y, x->degree);
    if (x == x->right)
    {
        y->child = NULL;
    }
    else
    {
        y->child = x->right;
    }
    x->parent = NULL;
    x->left = x->right = x;
    x->marked = false;
    FibNodeAdd(x, heap->min);
}

//级联剪切
static void FibHeapCascadingCut(FibHeap * heap, FibNode * y)
{
    FibNode * z = y->parent;
    if (NULL != z)
    {
        if (y->marked == false)
        {
            y->marked = true;
        }
        else
        {
            FibHeapCut(heap, y, z);
            FibHeapCascadingCut(heap, z);
        }
    }
}

//修改度数
void renewDegree(FibNode * parent, int degree)
{
    parent->degree -= degree;
    if (parent-> parent != NULL)
    {
        renewDegree(parent->parent, degree);
    }
}

//删除结点
void FibHeapDelete(FibHeap * heap, FibNode * x)
{
    FibHeapDecrease(heap, x, INT_MIN);
    FibHeapExtractMin(heap);
}

//堆内搜索关键字
FibNode * FibHeapSearch(FibHeap * heap, int key)
{
    return FibNodeSearch(heap->min, key);
}

//被FibHeapSearch调用
static FibNode * FibNodeSearch(FibNode * x, int key)
{
    FibNode * w = x, * y = NULL;
    if (x != NULL)
    {
        do
        {
            if (w->key == key)
            {
                y = w;
                break;
            }
            else if (NULL != (y = FibNodeSearch(w->child, key)))
            {
                break;
            }
            w = w->right;
        }
        while (w != x);
    }
    return y;
}

//销毁堆
void FibHeapDestory(FibHeap * heap)
{
    FibNodeDestory(heap->min);
    free(heap);
    heap = NULL;
}

//被FibHeapDestory调用
static void FibNodeDestory(FibNode * x)
{
    FibNode * p = x, *q = NULL;
    while (p != NULL)
    {
        FibNodeDestory(p->child);
        q = p;
        if (p -> left == x)
        {
            p = NULL;
        }
        else
        {
            p = p->left;
        }
        free(q->right);
    }
}

//输出打印堆
static void FibHeapPrint(FibHeap * heap)
{
    printf("The keyNum = %d\nThe sequence of printing is: Heap->min , its children if ever and then its left\n", heap->keyNum);
    FibNodePrint(heap->min);
    puts("\n");
};

//被FibHeapPrint调用
static void FibNodePrint(FibNode * x)
{
    FibNode * p = NULL;
    if (NULL == x)
    {
        return ;
    }
    p = x;
    do
    {
        printf(" (");
        printf("%d", p->key);
        if (p->child != NULL)
        {
            FibNodePrint(p->child);
        }
        printf(") ");
        p = p->left;
    }
    while (x != p);
}

int keys[10] = {1, 2, 3, 4, 5, 6, 7, 9, 10, 11};

int main()
{
    FibHeap * heap = NULL;
    FibNode * x = NULL;
    heap = FibHeapMake();
    FibHeapInsertKeys(heap, keys, 10);
    FibHeapPrint(heap);

    x = FibHeapExtractMin(heap);
    printf("抽取最小值%d之后:\n", x->key);
    FibHeapPrint(heap);

    x = FibHeapSearch(heap, 11);
    if (NULL != x)
    {
        printf("查找%d成功,", x->key);
        FibHeapDecrease(heap, x, 8);
        printf("减小到%d后:\n", x->key);
        FibHeapPrint(heap);
    }

    x = FibHeapSearch(heap, 6);
    if (NULL != x)
    {
        printf("查找%d成功,", x->key);
        FibHeapDecrease(heap, x, 1);
        printf("减小到%d后:\n", x->key);
        FibHeapPrint(heap);
    }

    x = FibHeapSearch(heap, 7);
    if (NULL != x)
    {
        printf("删除%d成功:\n", x->key);
        FibHeapDelete(heap, x);
        FibHeapPrint(heap);
    }

    FibHeapDestory(heap);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值