Kruskal最小生成树

本代码实现的是Kruskal发实现最小生成树,定义见《算法导论》。使用的文件MapInfo.txt的内容如下:
h 1 g
g 2 f
i 2 c
a 4 b
c 4 f
i 6 g
i 7 h
c 7 d
b 8 c
a 8 h
d 9 e
f 10 e
b 11 h
d 14 f
左边和右边的字符分别代表两个节点,中间的数字表示两个节点所在边的权重。
代码实现如下:

/*
 * Kruskal方法做最小生成树
 * 使用最小堆排序的方法来获取权重最小的边
 * 使用单向链表来保存森林中所有树
 *          Author: StoryMonster
 *Last Change Date: 2016/7/1
 */


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


typedef struct MapEdge
{
    char NodeName1;
    char NodeName2;
    int  weight;
} MapEdge;
typedef struct PealNode
{
    MapEdge *edge;
    int index;
    struct PealNode *father;
    struct PealNode *left;
    struct PealNode *right;
} PealNode;
typedef struct MinTree
{
    MapEdge *edge;              //以边为节点包含的内容
    struct MinTree *father;
    struct MinTree *left;
    struct MinTree *right;
} MinTree;
typedef struct TreeChain
{
    MinTree *tree;
    TreeChain *next;
} TreeChain;
static void      ReadConfigFile(void);  //读取文件信息并将信息存入最小堆
static bool      PutIntoMinPeal(PealNode *, PealNode *);        //将堆节点存入最小堆中
static void      FixMinPeal(PealNode *root);                //恢复最小堆的性质
static void   GetTheMinNode(PealNode *, PealNode *);//获取以第一个参数为根结点的堆中的最小节点,保存在第二个参数中
static PealNode  *GetMaxIndexNode(PealNode *);          //返回下标最大的节点
static void      BuildTheMinTree(void);                 //生成最小生成树
static void      InsertTreeToChain(TreeChain *);            //将树插入到链表中
static MinTree   *GetTheTree(char NodeName);            //返回链表中包含名为NodeName的节点的树
static bool      InThisTree(MinTree *, char NodeName);  //判断树中是否有包含名为NodeName的节点的边
static void      UnionTwoTree(MinTree *tree1, MinTree *tree2, MinTree * NewTree, MapEdge *RootEdge);//合并两棵树
static void      DeleteNodeFromTreeChain(MinTree *);            //删除森林从的一棵树
static void      CreatTree(MapEdge *);                  //创建一棵树并将之保存到链表中
static void      InsertToTree(MinTree *, MapEdge *);            //向指定树中插入一个节点
static void      ShowThisMinTree(MinTree *);                //打印最小生成树的信息


PealNode  *PealRoot  = (PealNode *)malloc(sizeof(PealNode));
TreeChain *ChainHead = (TreeChain *)malloc(sizeof(TreeChain));

int PealNodeCount  = 0;
int TreeCount      = 0;


void ShowThisMinTree(MinTree *root)
{
    if(root == NULL) return ;
    std::cout << (root->edge)->NodeName1<< "  "<< (root->edge)->NodeName2 << "  "<< (root->edge)->weight << std::endl;
    ShowThisMinTree(root->left);
    ShowThisMinTree(root->right);
}
void BuildTheMinTree(void)
{
    while(PealNodeCount > 0)
    {

        PealNode *node = (PealNode *)malloc(sizeof(PealNode));
        GetTheMinNode(PealRoot,node);
        MapEdge *edge = node->edge;
        MinTree *tree1 = GetTheTree(edge->NodeName1);
        MinTree *tree2 = GetTheTree(edge->NodeName2);
        if((tree1 == tree2)&&(tree1 != NULL)) continue;
        if(tree1 == NULL && tree2 == NULL)  CreatTree(edge);
        if(tree1 != NULL && tree2 == NULL)  InsertToTree(tree1,edge);
        if(tree1 == NULL && tree2 != NULL)  InsertToTree(tree2,edge);
        if(tree1 != NULL && tree2 != NULL)
        {
            MinTree *NewTree = (MinTree *)malloc(sizeof(MinTree));
            UnionTwoTree(tree1,tree2,NewTree,edge);
        }
    }
}
/*
   此处往最小树中插入节点,节点排列与堆类似是最好的,但是若是做成与堆类似的话,用广度搜索的方式是最好的,但是考虑到广度搜索会增加代码量,故而在此处使用这种生成树的方式。当前方式生成的树会是极左的树
 */
void InsertToTree(MinTree *tree, MapEdge *edge)
{
    MinTree *p = tree;
    MinTree *p1 = (MinTree *)malloc(sizeof(MinTree));
    p1->edge = edge;
    p1->left = NULL;
    p1->right = NULL;
    p1->father = NULL;
    while(p != NULL)
    {
        if(p->left == NULL)
        {
            p->left = p1;
            p1->father = p;
            break;
        }
        else
        {
            if(p->right == NULL)
            {
                p->right = p1;
                p1->father = p;
                break;
            }
        }
        p = p->left;
    }
}
void CreatTree(MapEdge *edge)
{
    MinTree *tree = (MinTree *)malloc(sizeof(MinTree));
    tree->father = NULL;
    tree->left   = NULL;
    tree->right  = NULL;
    tree->edge   = edge;
    TreeChain *chain = (TreeChain *)malloc(sizeof(TreeChain));
    chain->tree  = tree;
    chain->next  = NULL;
    InsertTreeToChain(chain);
}
void DeleteNodeFromTreeChain(MinTree *tree)
{
    TreeCount--;
    TreeChain *p = ChainHead;
    if(ChainHead->tree == tree)
    {
        ChainHead = ChainHead->next;
        return ;
    }
    while((p->next)->tree != tree) p = p->next;
    TreeChain *p1 = p->next;
    p->next = p1->next;
}
void UnionTwoTree(MinTree *tree1, MinTree *tree2, MinTree *NewTree, MapEdge *RootEdge)
{
    NewTree->left = tree1;
    NewTree->right = tree2;
    NewTree->father = NULL;
    tree1->father = NULL;
    tree2->father = NULL;
    NewTree->edge = RootEdge;
    DeleteNodeFromTreeChain(tree1);
    DeleteNodeFromTreeChain(tree2);
    TreeChain *chain = (TreeChain *)malloc(sizeof(TreeChain));
    chain->tree = NewTree;
    chain->next = NULL;
    InsertTreeToChain(chain);
}
bool InThisTree(MinTree *root,char NodeName)
{
    if(root == NULL) return false;
    if((root->edge)->NodeName1 == NodeName || (root->edge)->NodeName2 == NodeName)
    {
        return true;
    }
    else
    {
        bool result = InThisTree(root->left, NodeName);
        if(result == false) result = InThisTree(root->right, NodeName);
        return result;
    }
}
MinTree *GetTheTree(char NodeName)
{
    TreeChain *p = ChainHead;
    while(p!=NULL)
    {
        if(InThisTree(p->tree, NodeName))
        {
            return p->tree;
        }
        p = p->next;
    }
    return NULL;
}
void InsertTreeToChain(TreeChain * chain)
{
    TreeCount++;
    if(ChainHead == NULL)
    {
        ChainHead = chain;
        return ;
    }
    TreeChain *p = ChainHead;
    while(p->next != NULL) p = p->next;
    p->next = chain;
}   
PealNode *GetMaxIndexNode(PealNode *root)
{
    if(root == NULL)
    {
        return NULL;
    }
    else
    {
        if(root->index == PealNodeCount)
        {
            return root;
        }
        PealNode *result = GetMaxIndexNode(root->left);
        if(result == NULL)
        {
            return GetMaxIndexNode(root->right);
        }
        else return result;
    }
}
void GetTheMinNode(PealNode *root, PealNode *MinNode)
{
    MinNode->edge = root->edge;
    PealNode *p = GetMaxIndexNode(root);
    PealNodeCount--;
    if(p == root);
    else
    {
        root->edge = p->edge;
        if(p == (p->father)->left)
        {
            (p->father)->left = NULL;
        }
        else (p->father)->right = NULL;
        p->father = NULL;
        FixMinPeal(root);
    }
    free(p);
    p = NULL;
}
void FixMinPeal(PealNode *root)
{
    if(root->left == NULL) return ;
    else
    {
        PealNode *r_left = root->left;
        if((r_left->edge)->weight < (root->edge)->weight)
        {
            MapEdge *edgeTemp = r_left->edge;
            r_left->edge = root->edge;
            root->edge = edgeTemp;
            if(root->father != NULL) FixMinPeal(root->father);
        }
        FixMinPeal(r_left);
    }
    if(root->right == NULL) return ;
    else
    {
        PealNode *r_right = root->right;
        if((r_right->edge)->weight < (root->edge)->weight)
        {
            MapEdge *edgeTemp = r_right->edge;
            r_right->edge = root->edge;
            root->edge = edgeTemp;
            if(root->father != NULL) FixMinPeal(root->father);
        }
        FixMinPeal(r_right);
    }
}
bool PutIntoMinPeal(PealNode * root, PealNode *node)
{
    if(PealRoot == NULL)
    {
        PealRoot = node;
        return true;
    }
    if(root == NULL)
    {
        return false;
    }
    if((root->index)*2 == (node->index))
    {
        root->left = node;
        node->father = root;
        return true;
    }
    if((root->index)*2+1 == node->index)
    {
        root->right = node;
        node->father = root;
        return true;
    }
    if(PutIntoMinPeal(root->left,node)== false)
    {
        return PutIntoMinPeal(root->right,node);
    }
    else return true;
}
void ReadConfigFile(void)
{
    FILE *fp = fopen("MapInfo.txt","rb");
    if(!fp)
    {
        std::cout << "Open MapInfo.txt failed!" << std::endl;
        fp = NULL;
        return ;
    }
    int index = 1;
    while(1)
    {
        MapEdge *edge = (MapEdge *)malloc(sizeof(MapEdge));
        int n = fscanf(fp,"%c %d %c\n",&edge->NodeName1,&edge->weight,&edge->NodeName2);
        if(n < 1)
        {
            free(edge);
            edge = NULL;
            break;
        }
    //  std::cout << edge->NodeName1<<edge->weight<<edge->NodeName2<<"**"<<std::endl;
        PealNode *node = (PealNode *)malloc(sizeof(PealNode));
        node->edge  = edge;
        node->index = index++;
        node->father= NULL;
        node->left  = NULL;
        node->right = NULL;
        PutIntoMinPeal(PealRoot, node);
        PealNodeCount++;
    }
    fclose(fp);
    fp = NULL;
}
int main()
{
    PealRoot  = NULL;
    ChainHead = NULL;
    ReadConfigFile();
    FixMinPeal(PealRoot);
    BuildTheMinTree();
    ShowThisMinTree(ChainHead->tree);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值