并查集实现Kruskal算法
来源:互联网 发布:如何评价新东方 知乎 编辑:程序博客网 时间:2024/05/01 15:18
#include<stdio.h>#include<stdlib.h>#define MAXVEX 100 //最大顶点数#define MAXSIZE 20#define OK 1#define ERROR 0typedef char VertexType; //顶点typedef int EdgeType; //权值#define INFINITY 65535 /*用65535来代表∞*/#define UNVISITED -1 //标记未访问#define VISITED 1 //标记未访问//并查集时用到typedef struct parTreeNode{ VertexType value; //顶点(结点)元素 int nCount; //子树元素数目 struct parTreeNode * parent; //父结点指针}parTreeNode;typedef struct{ int from; //边的始点 int to; //边的终点 EdgeType weight; //权重}Edge; //边的结构//图的结构typedef struct{ int numVertex; //顶点个数 int numEdge; //边的个数 parTreeNode vexs[MAXVEX]; /*顶点表*/ int Indegree[MAXVEX]; //顶点入度 int Mark[MAXVEX]; //标记是否被访问过 EdgeType arc[MAXVEX][MAXVEX]; //边表 Edge MST[MAXVEX]; //数组MST用于保存最小生成树的边}Graph;typedef int Status;typedef Edge ElemType; //定义为Edge类型//最小堆的存储结构typedef struct { ElemType heapArray[MAXSIZE]; int length;}MinHeap;//返回依附于顶点的第一条边Edge FirstEdge(Graph * G,int oneVertex);//返回与preEdge有相同顶点的下一条边Edge NextEdge(Graph * G,Edge preEdge);//判断是否为边bool IsEdge(Edge oneEdge);//返回node结点的根结点parTreeNode * Find(parTreeNode * node){ parTreeNode * pointer=node; while(pointer->parent!=NULL) { pointer=pointer->parent; } return pointer;}//判断结点i和j是否有相同的根结点bool Different(Graph * G,int i,int j){ parTreeNode * pointer_i=Find(&G->vexs[i]); //找到结点i的根 parTreeNode * pointer_j=Find(&G->vexs[j]); //找的结点j的根 return pointer_i!=pointer_j; //若结点i和j的根结点不相同返回true}//合并void Union(Graph * G,int i,int j){ parTreeNode * pointer_i=Find(&G->vexs[i]); //找到结点i的根 parTreeNode * pointer_j=Find(&G->vexs[j]); //找的结点j的根 if(pointer_i!=pointer_j) { if(pointer_i->nCount>=pointer_j->nCount) { pointer_j->parent=pointer_i; //把结点i设置为j的父结点 pointer_i->nCount=pointer_i->nCount+pointer_j->nCount; } else { pointer_i->parent=pointer_j; //把结点j设置为i的父结点 pointer_j->nCount=pointer_i->nCount+pointer_j->nCount; } }}//初始化堆数组Status Init_heapArray(Graph * G,MinHeap * M){ for(int i=0;i<G->numVertex;i++) { for(Edge e=FirstEdge(G,i);IsEdge(e);e=NextEdge(G,e)) { if(e.from<e.to) //对于无向图,防止重复插入边 { M->heapArray[M->length]=e; M->length++; } } } return OK;}//对最小堆初始化Status Init_MinHeap(Graph * G,MinHeap * M){ M->length=0; Init_heapArray(G,M); return OK;}int MinHeap_Leftchild(int pos) //返回左孩子的下标{ return 2*pos+1;}int MinHeap_Rightchild(int pos) //返回右孩子的下标{ return 2*pos+2;}int MinHeap_Parent(int pos) //返回双亲的下标{ return (pos-1)/2;}void MinHeap_SiftDown(MinHeap * M,int left){ int i=left; //标识父结点 int j=MinHeap_Leftchild(i); //用于记录关键值较小的子结点 ElemType temp=M->heapArray[i]; //保存父结点 while(j<M->length) //过筛 { if((j<M->length-1)&&(M->heapArray[j].weight>M->heapArray[j+1].weight)) //若有右子结点,且小于左子结点 { j++; //j指向右子结点 } if(temp.weight>M->heapArray[j].weight) //如果父结点大于子结点的值则交换位置 { M->heapArray[i]=M->heapArray[j]; i=j; j=MinHeap_Leftchild(j); } else //堆序性满足时则跳出 { break; } } M->heapArray[i]=temp;}void MinHeap_SiftUp(MinHeap * M,int position) //从position开始向上调整{ int temppos=position; ElemType temp=M->heapArray[temppos]; //记录当前元素 while((temppos>0) && (M->heapArray[MinHeap_Parent(temppos)].weight>temp.weight)) //temppos>0,结束于根结点 { M->heapArray[temppos]=M->heapArray[MinHeap_Parent(temppos)]; temppos=MinHeap_Parent(temppos); } M->heapArray[temppos]=temp;}void Swap(MinHeap * M,int data1,int data2){ ElemType temp; temp=M->heapArray[data1]; M->heapArray[data1]=M->heapArray[data2]; M->heapArray[data2]=temp;}//建立最小堆void Create_MinHeap(MinHeap * M){ for(int i=M->length/2-1;i>=0;i--) { MinHeap_SiftDown(M,i); }}//删除最小堆的最小值Status MinHeap_Delete(MinHeap * M,ElemType * MinElem){ if(M->length==0) { printf("不能删除,堆已空!\n"); return ERROR; } else { Swap(M,0,--M->length); if(M->length>1) { MinHeap_SiftDown(M,0); } *MinElem=M->heapArray[M->length]; return OK; }}//初始化图void InitGraph(Graph * G,int numVert,int numEd ) //传入顶点个数,边数{ G->numVertex=numVert; G->numEdge=numEd; for(int i=0;i<numVert;i++) { G->vexs[i].nCount=1; G->vexs[i].parent=NULL; G->Mark[i]=UNVISITED; G->Indegree[i]=0; for(int j=0;j<numVert;j++) { G->arc[i][j]=INFINITY; if(i==j) { G->arc[i][j]=0; } } } return ;}//判断是否为边bool IsEdge(Edge oneEdge){ if(oneEdge.weight>0 && oneEdge.weight!=INFINITY && oneEdge.to>=0) { return true; } else { return false; }}//建立有向图的邻接矩阵void CreatGraph(Graph * G){ int i,j,k,w; printf("请输入%d个顶点元素:\n",G->numVertex); for(i=0;i<G->numVertex;i++) { scanf(" %c",&G->vexs[i].value); } for(k=0;k<G->numEdge;k++) { printf("请输入边(Vi,Vj)的下标Vi,Vj,和权重w:\n"); scanf("%d%d%d",&i,&j,&w); G->Indegree[j]++; G->arc[i][j]=w; }}//返回顶点个数int VerticesNum(Graph * G){ return G->numVertex;}//返回依附于顶点的第一条边Edge FirstEdge(Graph * G,int oneVertex){ Edge firstEdge; firstEdge.from=oneVertex; for(int i=0;i<G->numVertex;i++) { if(G->arc[oneVertex][i]!=0 && G->arc[oneVertex][i]!=INFINITY) { firstEdge.to=i; firstEdge.weight=G->arc[oneVertex][i]; break; } } return firstEdge;} //返回oneEdge的终点int ToVertex(Edge oneEdge){ return oneEdge.to;}//返回与preEdge有相同顶点的下一条边Edge NextEdge(Graph * G,Edge preEdge){ Edge myEdge; myEdge.from=preEdge.from; //边的始点与preEdge的始点相同 if(preEdge.to<G->numVertex) //如果preEdge.to+1>=G->numVertex;将不存在下一条边 for(int i=preEdge.to+1;i<G->numVertex;i++) //找下一个arc[oneVertex][i] { //不为0的i if(G->arc[preEdge.from][i]!=0 && G->arc[preEdge.from][i]!=INFINITY) { myEdge.to=i; myEdge.weight=G->arc[preEdge.from][i]; break; } } return myEdge;}//设置一条边Edge Setedge(int from,int to,int weight){ Edge edge; edge.from=from; edge.to=to; edge.weight=weight; return edge;}void Edge_to_MST(Graph * G,Edge e,int num){ G->MST[num]=e;}//打印出MST数组void Print_MST(Graph * G,int n){ for(int i=0;i<n;i++) { printf("elem:%c->%c Edge:(%d,%d) length:%d\n",G->vexs[G->MST[i].from].value,G->vexs[G->MST[i].to].value,G->MST[i].from,G->MST[i].to,G->MST[i].weight); } printf("\n");}void Kruskal(Graph * G,MinHeap * M){ Init_MinHeap(G,M); Create_MinHeap(M); int MSTtag=0; int EquNum=G->numVertex; //开始n个顶点分别作为一个等价类 while(EquNum>1) //当等价类的个数大于1时合并等价类 { Edge e; if(M->length!=0) //堆不为空 { MinHeap_Delete(M,&e); //获得一条权值最小的边 } if(M->length==0 || e.weight==INFINITY) { printf("不存在最小生成树!\n"); return ; } int from=e.from; int to=e.to; if(Different(G,from,to)) //边e的两个顶点不在一个等价类 { Union(G,from,to); //将边e的两个顶点所在的等价类合并为一个 Edge_to_MST(G,e,MSTtag++); EquNum--; } } Print_MST(G,MSTtag);}int main(){ Graph G; MinHeap M; int numVert,numEd; printf("请输入顶点数和边数:\n"); scanf("%d%d",&numVert,&numEd); InitGraph(&G,numVert,numEd ); CreatGraph(&G); Kruskal(&G,&M); return 0;}
0 0
- Kruskal算法+并查集实现
- 并查集实现Kruskal算法
- Kruskal算法的并查集实现
- [容易] kruskal 算法并查集实现
- Kruskal算法 (并查集)
- Kruskal算法并查集和最小堆实现
- 最小生成树Kruskal算法+并查集实现
- hdoj 还是畅通工程 并查集实现Kruskal算法
- 最小生成树Kruskal算法+并查集实现
- 并查集实现最小生成树的kruskal算法
- 运用并查集与最小堆实现Kruskal算法
- hdu1879(并查集+Kruskal算法)
- HDU1863并查集和kruskal算法
- 图论 Kruskal算法 并查集
- poj1251 Kruskal算法+并查集
- Kruskal算法(并查集)
- kruskal+ 并查集
- Kruskal+并查集
- Cocos2d-x学习笔记(九)纹理CCTexture2D和精灵CCSprite
- Android GradientDrawable高级应用 以后完全用不上美工了
- MobclickAgent——友盟用户分析工具
- vbox下虚拟机同宿主机互相ping,且虚拟机能访问网络的配置
- 记得去实现自己的梦想,dream is power
- 并查集实现Kruskal算法
- iOS 调用用户设置界面
- Java中字符串的使用
- android如何屏蔽掉home键
- 黑马程序员----java线程
- 搭建一个RESTFUL风格的Web Service (Maven版本)
- C/C++文字常量与常变量的概念与区别
- 文章标题
- NGS项目六:R语言与Bioconductor分析affymetrix芯片