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
左边和右边的字符分别代表两个节点,中间的数字表示两个节点所在边的权重。
代码实现如下:
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; }
相关文章推荐
- 如何组织构建多文件 C 语言程序(二)
- 如何写好 C main 函数
- Lua和C语言的交互详解
- 关于C语言中参数的传值问题
- 简要对比C语言中三个用于退出进程的函数
- 深入C++中API的问题详解
- 基于C语言string函数的详解
- C语言中fchdir()函数和rewinddir()函数的使用详解
- C语言内存对齐实例详解
- C语言编程中统计输入的行数以及单词个数的方法
- C语言自动生成enum值和名字映射代码
- C语言练习题:自由落体的小球简单实例
- 使用C语言判断英文字符大小写的方法
- c语言实现的带通配符匹配算法
- C语言实现顺序表基本操作汇总
- C语言中进制知识汇总
- C语言判断一个数是否是2的幂次方或4的幂次方
- C语言中计算正弦的相关函数总结
- 使用C语言详解霍夫曼树数据结构
- C语言实现选择排序、冒泡排序和快速排序的代码示例