您的位置:首页 > 编程语言 > C语言/C++

Kruskal最小生成树

2016-07-10 14:16 453 查看
本代码实现的是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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息