图的建立:
大家都知道一般创建图可以用两种存储结构:邻接矩阵和邻接表。这里我们采取邻接矩阵的方法。。这两种具体的结构在这里不介绍了。
struct MyGraphic { int vertex,edge; //顶点和边 int Matrix[MAX_VERTEX][MAX_VERTEX]; //临接矩阵 };
这就是我做的创建图基本的结构,包括:点数(vertex),边数(edge),存储具体的边( 邻接矩阵)。
下面我们就用这个来创建一个简单的无向图:
#include<iostream> using namespace std; #define MAX_VERTEX 10 struct MyGraphic { int vertex,edge; //顶点和边 int Matrix[MAX_VERTEX][MAX_VERTEX]; //临接矩阵 }; void CreateGraphic(MyGraphic& myGraphic) { cout<<"请输入顶点数和边数:"; cin>>myGraphic.vertex>>myGraphic.edge; cout<<endl; int i,j; for(i=0;i<myGraphic.vertex;i++) { for(j=0;j<myGraphic.vertex;j++) { myGraphic.Matrix[i][j]=0; } } int vertex1,vertex2; for(i=0;i<myGraphic.edge;i++) { cout<<"请输入第"<<i<<"条边的两个顶点:"; cin>>vertex1>>vertex2; myGraphic.Matrix[vertex1][vertex2]=1; myGraphic.Matrix[vertex2][vertex1]=1; //无向图 cout<<endl; } } void printGraphicMatrix(MyGraphic graphic) { int i,j; for(i=0;i<graphic.vertex;i++) { for(j=0;j<graphic.vertex;j++) { cout<<graphic.Matrix[i][j]<<" "; } cout<<endl; } } void main() { MyGraphic myGraphic; CreateGraphic(myGraphic); printGraphicMatrix(myGraphic); }
本来想画个图的,但是没有好的工具。
图的遍历:
深度遍历:
bool isVisit[MAX_VERTEX];
struct EdgeInfo { int weight; //权重 int flag; //标记是否有边 };
void depth_visit(MyGraphic graphic,int vertex) { cout<<" 节点"<<vertex<<" "; isVisit[vertex]=true; int j; for(j=0;j<graphic.vertex;j++) { if(graphic.Matrix[vertex][j].flag&&!isVisit[j]) { depth_visit(graphic,j); } } } //深度遍历 void depth_traverse(MyGraphic graphic) { int i; for(i=0;i<graphic.vertex;i++) { if(!isVisit[i]) { depth_visit(graphic,i); } } }
广度遍历:
vector<int>g_currentTraverse; //正在访问的节点集合 vector<int>g_waitingTraverse;//等待访问的节点集合
void width_visit(MyGraphic graphic) { if(g_currentTraverse.empty()) return; vector<int>::iterator it=g_currentTraverse.begin(); int j; for(it;it!=g_currentTraverse.end();it++) { if(!isVisit[*it]) { cout<<"节点"<<*it<<" "; isVisit[*it]=true; } for(j=0;j<graphic.vertex;j++) { if(graphic.Matrix[*it][j].flag&&!isVisit[j]) { g_waitingTraverse.push_back(j); } } } g_currentTraverse.clear(); g_currentTraverse=g_waitingTraverse; g_waitingTraverse.clear(); width_visit(graphic); } //广度遍历 void width_traverse(MyGraphic graphic) { int i; for(i=0;i<graphic.vertex;i++) { if(!isVisit[i]) { g_currentTraverse.push_back(i); width_visit(graphic); } } }
完整的遍历程序:
#include<iostream> #include<vector> #include<list> using namespace std; #define MAX_VERTEX 10 bool isVisit[MAX_VERTEX]; vector<int>g_currentTraverse; //正在访问的节点集合 vector<int>g_waitingTraverse;//等待访问的节点集合 struct EdgeInfo { int weight; //权重 int flag; //标记是否有边 }; struct MyGraphic { int vertex,edge; //顶点和边 EdgeInfo Matrix[MAX_VERTEX][MAX_VERTEX]; //临接矩阵 }; void CreateGraphic(MyGraphic& myGraphic) //图的建立,初始化 { cout<<"请输入顶点数和边数:"; cin>>myGraphic.vertex>>myGraphic.edge; cout<<endl; int i,j; for(i=0;i<myGraphic.vertex;i++) { for(j=0;j<myGraphic.vertex;j++) { myGraphic.Matrix[i][j].flag=0; myGraphic.Matrix[i][j].weight=0; } } int vertex1,vertex2; int weight; for(i=0;i<myGraphic.edge;i++) { cout<<"请输入第"<<i<<"条边的两个顶点和权重:"; cin>>vertex1>>vertex2>>weight; myGraphic.Matrix[vertex1][vertex2].flag=1; myGraphic.Matrix[vertex2][vertex1].flag=1; //无向图 myGraphic.Matrix[vertex1][vertex2].weight=weight; myGraphic.Matrix[vertex2][vertex1].weight=weight; cout<<endl; } } void depth_visit(MyGraphic graphic,int vertex) { cout<<" 节点"<<vertex<<" "; isVisit[vertex]=true; int j; for(j=0;j<graphic.vertex;j++) { if(graphic.Matrix[vertex][j].flag&&!isVisit[j]) { depth_visit(graphic,j); } } } //深度遍历 void depth_traverse(MyGraphic graphic) { int i; for(i=0;i<graphic.vertex;i++) { if(!isVisit[i]) { depth_visit(graphic,i); } } } void width_visit(MyGraphic graphic) { if(g_currentTraverse.empty()) return; vector<int>::iterator it=g_currentTraverse.begin(); int j; for(it;it!=g_currentTraverse.end();it++) { if(!isVisit[*it]) { cout<<"节点"<<*it<<" "; isVisit[*it]=true; } for(j=0;j<graphic.vertex;j++) { if(graphic.Matrix[*it][j].flag&&!isVisit[j]) { g_waitingTraverse.push_back(j); } } } g_currentTraverse.clear(); g_currentTraverse=g_waitingTraverse; g_waitingTraverse.clear(); width_visit(graphic); } //广度遍历 void width_traverse(MyGraphic graphic) { int i; for(i=0;i<graphic.vertex;i++) { if(!isVisit[i]) { g_currentTraverse.push_back(i); width_visit(graphic); } } } //输出图信息 void printGraphicMatrix(MyGraphic graphic) { int i,j; //输出边的信息 for(i=0;i<graphic.vertex;i++) { for(j=0;j<graphic.vertex;j++) { cout<<graphic.Matrix[i][j].flag<<" "; } cout<<endl; } cout<<endl; //输出边的权重 for(i=0;i<graphic.vertex;i++) { for(j=0;j<graphic.vertex;j++) { cout<<graphic.Matrix[i][j].weight<<" "; } cout<<endl; } } //遍历图的初始化 void initVisit(MyGraphic graphic) { int i; for(i=0;i<graphic.vertex;i++) { isVisit[i]=false; } } void main() { MyGraphic myGraphic; CreateGraphic(myGraphic); printGraphicMatrix(myGraphic); initVisit(myGraphic); cout<<"深度遍历:"<<endl; depth_traverse(myGraphic); initVisit(myGraphic); cout<<endl; cout<<"广度遍历:"<<endl; width_traverse(myGraphic); }
最小生成树(Prime算法)
普利姆(Prim)算法思想
设:N =(V , E)是个连通网,另设U为最小生成树的顶点集,TE为最小生成树的边集。
普利姆(Prim)算法步骤:
(1)初始状态: U ={u0 },( u0 ∈V ),TE= φ,
(2)在u∈U ,v∈(V-U)所有的边(u,v)∈E中,找一条代价最小的边(u0,v0),并将边(u0,v0)并入集合TE,同时v0并入U。
(3)重复(2),直到U=V为止。
此时TE中必有n-1条边,T=(V,{TE})就是最小生成树。
注:在最小生成树的生成过程中,所选的边都是一端在U中,另一端在V-U中。选最小边的过程是一个向集合U中添加顶点的过程。
list<int>g_EleInPrimeTree; //U集合,即已经加入最小生成树的点集合 list<int>g_EleNotInPrimeTree; //V-U集合
#define MAX_WEIGHT 65536
void prime(MyGraphic graphic) { if(g_EleNotInPrimeTree.empty()) return; int min_weight=MAX_WEIGHT; int index1=0; int index2=0; list<int>::iterator it_inPrimeTree=g_EleInPrimeTree.begin(); list<int>::iterator it_notInPrimeTree; list<int>::iterator temp_it=NULL; for(it_inPrimeTree;it_inPrimeTree!=g_EleInPrimeTree.end();it_inPrimeTree++) { for(it_notInPrimeTree=g_EleNotInPrimeTree.begin();it_notInPrimeTree!=g_EleNotInPrimeTree.end();it_notInPrimeTree++) { if(graphic.Matrix[*it_inPrimeTree][*it_notInPrimeTree].flag &&graphic.Matrix[*it_inPrimeTree][*it_notInPrimeTree].weight<min_weight) { min_weight=graphic.Matrix[*it_inPrimeTree][*it_notInPrimeTree].weight; index1=*it_inPrimeTree; index2=*it_notInPrimeTree; temp_it=it_notInPrimeTree; } } } if(index2&&temp_it!=NULL) { g_EleInPrimeTree.push_back(index2); cout<<"节点"<<index1<<"----"<<"节点"<<index2<<endl; g_EleNotInPrimeTree.erase(temp_it); prime(graphic); } } //求最小生成树的初始化 void initPrime(MyGraphic graphic) { int i; g_EleInPrimeTree.push_back(0); for(i=1;i<graphic.vertex;i++) { g_EleNotInPrimeTree.push_back(i); } }
我这里实现的很简单,也没优化代码。具体代码如下:
#include<iostream> #include<vector> #include<list> using namespace std; #define MAX_VERTEX 10 #define MAX_WEIGHT 65536 bool isVisit[MAX_VERTEX]; vector<int>g_currentTraverse; //正在访问的节点集合 vector<int>g_waitingTraverse;//等待访问的节点集合 list<int>g_EleInPrimeTree; //U集合,即已经加入最小生成树的点集合 list<int>g_EleNotInPrimeTree; //V-U集合 struct EdgeInfo { int weight; //权重 int flag; //标记是否有边 }; struct MyGraphic { int vertex,edge; //顶点和边 EdgeInfo Matrix[MAX_VERTEX][MAX_VERTEX]; //临接矩阵 }; void CreateGraphic(MyGraphic& myGraphic) //图的建立,初始化 { cout<<"请输入顶点数和边数:"; cin>>myGraphic.vertex>>myGraphic.edge; cout<<endl; int i,j; for(i=0;i<myGraphic.vertex;i++) { for(j=0;j<myGraphic.vertex;j++) { myGraphic.Matrix[i][j].flag=0; myGraphic.Matrix[i][j].weight=0; } } int vertex1,vertex2; int weight; for(i=0;i<myGraphic.edge;i++) { cout<<"请输入第"<<i<<"条边的两个顶点和权重:"; cin>>vertex1>>vertex2>>weight; myGraphic.Matrix[vertex1][vertex2].flag=1; myGraphic.Matrix[vertex2][vertex1].flag=1; //无向图 myGraphic.Matrix[vertex1][vertex2].weight=weight; myGraphic.Matrix[vertex2][vertex1].weight=weight; cout<<endl; } } void depth_visit(MyGraphic graphic,int vertex) { cout<<" 节点"<<vertex<<" "; isVisit[vertex]=true; int j; for(j=0;j<graphic.vertex;j++) { if(graphic.Matrix[vertex][j].flag&&!isVisit[j]) { depth_visit(graphic,j); } } } //深度遍历 void depth_traverse(MyGraphic graphic) { int i; for(i=0;i<graphic.vertex;i++) { if(!isVisit[i]) { depth_visit(graphic,i); } } } void width_visit(MyGraphic graphic) { if(g_currentTraverse.empty()) return; vector<int>::iterator it=g_currentTraverse.begin(); int j; for(it;it!=g_currentTraverse.end();it++) { if(!isVisit[*it]) { cout<<"节点"<<*it<<" "; isVisit[*it]=true; } for(j=0;j<graphic.vertex;j++) { if(graphic.Matrix[*it][j].flag&&!isVisit[j]) { g_waitingTraverse.push_back(j); } } } g_currentTraverse.clear(); g_currentTraverse=g_waitingTraverse; g_waitingTraverse.clear(); width_visit(graphic); } //广度遍历 void width_traverse(MyGraphic graphic) { int i; for(i=0;i<graphic.vertex;i++) { if(!isVisit[i]) { g_currentTraverse.push_back(i); width_visit(graphic); } } } //输出图信息 void printGraphicMatrix(MyGraphic graphic) { int i,j; //输出边的信息 for(i=0;i<graphic.vertex;i++) { for(j=0;j<graphic.vertex;j++) { cout<<graphic.Matrix[i][j].flag<<" "; } cout<<endl; } cout<<endl; //输出边的权重 for(i=0;i<graphic.vertex;i++) { for(j=0;j<graphic.vertex;j++) { cout<<graphic.Matrix[i][j].weight<<" "; } cout<<endl; } } //遍历图的初始化 void initVisit(MyGraphic graphic) { int i; for(i=0;i<graphic.vertex;i++) { isVisit[i]=false; } } void prime(MyGraphic graphic) { if(g_EleNotInPrimeTree.empty()) return; int min_weight=MAX_WEIGHT; int index1=0; int index2=0; list<int>::iterator it_inPrimeTree=g_EleInPrimeTree.begin(); list<int>::iterator it_notInPrimeTree; list<int>::iterator temp_it=NULL; for(it_inPrimeTree;it_inPrimeTree!=g_EleInPrimeTree.end();it_inPrimeTree++) { for(it_notInPrimeTree=g_EleNotInPrimeTree.begin();it_notInPrimeTree!=g_EleNotInPrimeTree.end();it_notInPrimeTree++) { if(graphic.Matrix[*it_inPrimeTree][*it_notInPrimeTree].flag &&graphic.Matrix[*it_inPrimeTree][*it_notInPrimeTree].weight<min_weight) { min_weight=graphic.Matrix[*it_inPrimeTree][*it_notInPrimeTree].weight; index1=*it_inPrimeTree; index2=*it_notInPrimeTree; temp_it=it_notInPrimeTree; } } } if(index2&&temp_it!=NULL) { g_EleInPrimeTree.push_back(index2); cout<<"节点"<<index1<<"----"<<"节点"<<index2<<endl; g_EleNotInPrimeTree.erase(temp_it); prime(graphic); } } //求最小生成树的初始化 void initPrime(MyGraphic graphic) { int i; g_EleInPrimeTree.push_back(0); for(i=1;i<graphic.vertex;i++) { g_EleNotInPrimeTree.push_back(i); } } void main() { MyGraphic myGraphic; CreateGraphic(myGraphic); printGraphicMatrix(myGraphic); initVisit(myGraphic); cout<<"深度遍历:"<<endl; depth_traverse(myGraphic); initVisit(myGraphic); cout<<endl; cout<<"广度遍历:"<<endl; width_traverse(myGraphic); //Prime树 cout<<endl; cout<<"最小生成树:"<<endl; initPrime(myGraphic); prime(myGraphic); }