#include "stdafx.h" #include<iostream> using namespace std; const int INF=65535; struct Graph { int *vex; int **arc; int numEdges,numVexes; }; void CreateGraph(Graph &G) { cout<<"请输入定点数和边数"<<endl; cin>>G.numVexes>>G.numEdges; G.vex=new int[G.numVexes];//为指向数组的指针 G.arc=new int*[G.numVexes];//为指针数组 for(int i=0;i<G.numVexes;i++) G.arc[i]=new int[G.numVexes]; cout<<"请输入顶点值"<<endl; for(int i=0;i<G.numVexes;i++)//初始化顶点 cin>>G.vex[i]; cout<<'\n'; for(int i=0;i<(G.numVexes);i++)//初始化边集数组 { for(int j=0;j<(G.numVexes);j++) { if(i==j) G.arc[i][j]=0; else G.arc[i][j]=INF; } } cout<<"请输入边的下标v1,v2权值w"<<endl;; int m=0,n=0,w=0; for(int a=0;a<(G.numEdges);a++)//注意这里的G.numEdges必须()起来,否则会出问题 { cin>>m>>n>>w; G.arc[m][n]=w; G.arc[n][m]=w; } } int _tmain(int argc, _TCHAR* argv[]) { Graph G; CreateGraph(G); for(int i=0;i<G.numVexes;i++) cout<<G.vex[i]; cout<<'\n'; for(int i=0;i<G.numVexes;i++) { for(int j=0;j<G.numVexes;j++) cout<<G.arc[i][j]<<' '; cout<<'\n'; } delete G.vex; delete G.arc; return 0; }
注意两点:
(1)这里的顶点数组和邻接矩阵均为指针,而邻接矩阵为指向数组的指针,一定要注意其初始化方式
(2)a<G.numVexes可能会出问题,所以记得打上()
void DFS(Graph &G,int i) { cout<<G.vex[i]<<endl; G.visited[i]=true; for(int j=0;j<G.numVexes;j++) { if(G.arc[i][j]!=INF && (!G.visited[j])) DFS(G,j); } } void DFSTraverse(Graph &G) { G.visited=new int[G.numVexes]; for(int i=0;i<G.numVexes;i++) G.visited[i]=false; for(int i=0;i<G.numVexes;i++) { if(!G.visited[i]) DFS(G,i); } }
思想:
(1)对于每一个点,都要打印它,以及和它有连接的,且没有访问过的点。
(2)这样就用到递归,函数由两部分组成,一个是打印本节点,另外的任务是访问和它有关的节点
(3)递归主体,如果满足条件,那么就让它去执行下一个相连节点
(3)函数部分,一定要做的是先打印。
void BFSTraverse(Graph &G) { G.visited=new int[G.numVexes]; for(int i=0;i<(G.numVexes);i++) G.visited[i]=false; queue<int> Q;//这才是默认使用queue的方式,和vector的使用是一样的 for(int i=0;i<G.numVexes;i++) { if(!G.visited[i]) { cout<<G.vex[i]<<endl;//此处保证就算没有连接 也可以打印出来 G.visited[i]=true; Q.push(i); while(Q.size())//递归都可以拆解成while循环来搞定,这个方法好,利用队列 { i=Q.front(); Q.pop(); for(int j=0;j<G.numVexes;j++) { if(G.arc[i][j]<INF && (!G.visited[j])) { cout<<G.vex[j]<<endl; G.visited[j]=true; Q.push(j); } } } } } }
思想:
(1)将堆栈转化成队列来实现
(2)从理论上来讲,递归形成了堆栈,队列就可以不用做递归,真是太巧妙了。
(3)果然是这样的,以后要尝试用队列+while循环来解决所有递归的问题。
<pre name="code" class="cpp">void MiniSpan_Prim(Graph &G) { int k=0; int *lowcost=new int[G.numVexes]; int *adjvex=new int[G.numVexes]; for(int i=0;i<G.numVexes;i++) lowcost[i]=INF;//lowcost初始化 for(int i=1;i<G.numVexes;i++)//找出与顶点0相邻的顶点,并置lowcost { if(G.arc[0][i]<INF) lowcost[i]=G.arc[0][i]; } lowcost[0]=0; for(int a=1;a<G.numVexes;a++)//找的次数 { int min=INF; for(int j=1;j<G.numVexes;j++)//找locost中最小的,标记下标 { if(lowcost[j]!=0 && lowcost[j]<min) { min=lowcost[j]; k=j; } } lowcost[k]=0;//说明该点已经找过 cout<<adjvex[k]<<" "<<k<<endl; for(int i=1;i<G.numVexes;i++)//从这一点触发,增加有权值的新点,需要和原来locost比较 { if(lowcost[i]!=0 && G.arc[k][i]<locost[i])//此处为修改 { lowcost[i]=G.arc[k][i]; adjvex[i]=k;//说明前一个点为k,这样就组成了一条边 } } } //打印操作 delete []lowcost; }
思想:
(1)找到和0相邻的点,有一批lowcost值
(2)找出这批lowcost值中最小值对应的点。标记为已经找过,并打印
(3)找这个点相邻的点,加入到lowcost中,回到步骤2
(4)特点就是不断刷lowcost的值,省去了queue
<pre name="code" class="cpp">#include "stdafx.h" #include<iostream> using namespace std; const int INF=65535; struct Edge { int begin; int end; int weight; }; struct Graph { int *vex; Edge *edges; int numEdges,numVexes; }; void CreateGraph(Graph &G) { cout<<"请输入顶点数和边数"<<endl; cin>>G.numVexes>>G.numEdges; G.vex=new int[G.numVexes];//为指向数组的指针 G.edges=new Edge[G.numEdges]; cout<<"请从小到大输入边"<<endl; for(int i=0;i<G.numEdges;i++) { cin>>G.edges[i].begin>>G.edges[i].end>>G.edges[i].weight; } } int find(int *parent,int f) { while(parent[f]>0) f=parent[f]; return f; } void MiniSpaceTree_Kruskal(Graph &G) { int m,n; int *parent=new int[G.numEdges](); for(int i=0;i<G.numEdges;i++) { n=find(parent,G.edges[i].begin); m=find(parent,G.edges[i].end); if(m!=n) { parent[n]=m;//此处为修改后的 cout<<G.edges[i].begin<<" "<<G.edges[i].end<<" "<<G.edges[i].weight<<'\n'; } } delete []parent;//注意数组的释放 } int _tmain(int argc, _TCHAR* argv[]) { Graph G; CreateGraph(G); MiniSpaceTree_Kruskal(G); delete []G.vex; delete []G.edges; return 0; }
思想:
(1)顶点输入序号必须是要按照从小到大输入,小的在前面
(2)边必须按照由小到大输入,这样才能是最小生成树
(3)不断加入稍微长的,由小端标记可以达到的大端。 如果已经标记,那么大端标记为小端,这样就能够从联通的一点找到另外一点。
(4)若加入的边,不构成回路,那么记下这条边。
(5)其中find函数这种找法很不错。
<pre name="code" class="cpp"><pre name="code" class="cpp">#include<iostream> using namespace std; const int INF=65535; struct Graph { int *vex; int **arc; int numEdges,numVexes; }; void CreateGraph(Graph &G) { } void ShortestPath_Dijkstra(Graph G,int v0,int *shortvalue,int *adjvex) { bool *visited=new bool[G.numVexes]; for(int i=0;i<G.numVexes;i++) visited[i]=false; visited[v0]=true; shortvalue[v0]=0; for(int i=0;i<G.numVexes;i++) { if(G.arc[v0][i]!=INF) { shortvalue[i]=G.arc[v0][i]; adjvex[i]=v0; } } for(int i=1;i<G.numVexes;i++)//找当前最近的点 { int min=INF; int k=0; for(int j=0;j<G.numVexes;j++) { if(!visited[j]&&shortvalue[j]<min) { min=shortvalue[j]; k=j; } } for(int j=0;j<G.numVexes;j++)//对相邻的点最短距离,进行更新 { if(!visited[j]&&min+G.arc[k][j]<shortvalue[j]) { shortvalue[j]=min+G.arc[k][j]; adjvex[j]=k;//标记其前一个点为k } } } delete []visited; }
思想:
(1)对刚开始的点置为访问过,更新和它相邻的点的距离。
(2)每一次都要找出一个最近且没有找过的点,标记它并更新和它相连点的距离
(3)重复2
(4)找完之后shortvalue为各个点到它的距离,adjvex为要到这个点其前一个点的下标
if(D[v][w]>D[v][k]+D[k][w]) { D[v][w]=D[v][k]+D[k][w]; P[v][w]=P[v][k]; }
#include<iostream> #include<stack> using namespace std; struct EdgeNode //邻接表结构 { int adjvex; //int weight; EdgeNode *next; }; struct VexNode { int in; int data; EdgeNode *fistedge; }; struct GraphList { VexNode *adjlist; int numVexes,numEdges; }; void CreateGraphList(GraphList &G) { cout<<"请输入顶点和边的数目"<<endl; cin>>G.numVexes>>G.numEdges; G.adjlist=new VexNode[G.numVexes]();//直接初始化 cout<<"请输入顶点的的data值"<<endl; for(int i=0;i<G.numVexes;i++) { cin>>G.adjlist[i].data; } cout<<"请输入边的出顶点,入顶点"<<endl; for(int i=0;i<G.numEdges;i++) { int in,out; cin>>in>>out; EdgeNode *edge=new EdgeNode(); edge->adjvex=out; edge->next=G.adjlist[in].fistedge;//利用前插法,这样就不需要遍历链表,而后插法需要先遍历到最后面才可以 G.adjlist[in].fistedge=edge; //修改入度 G.adjlist[out].in++; } cout<<"显示输出效果"<<endl; for(int i=0;i<G.numVexes;i++) { cout<<G.adjlist[i].in<<" ";//输出入度 EdgeNode *p=G.adjlist[i].fistedge; while(p) { cout<<p->adjvex; p=p->next; } cout<<'\n'; } } void TopLogicalSort(GraphList &G) { cout<<"输出拓扑排序"<<endl; stack<int> S; int count=0; for(int i=0;i<G.numVexes;i++) { if(G.adjlist[i].in==0) S.push(i); } while(S.size()) { int a=S.top(); S.pop(); count++; cout<<"v"<<a<<" "; EdgeNode *p=G.adjlist[a].fistedge; while(p) { if(!(--G.adjlist[p->adjvex].in))//注意是先-再使用 S.push(p->adjvex); p=p->next; } } if(count==G.numVexes) cout<<"TopLogicalSort ok"<<endl; else cout<<"TopLogicalSort error"<<endl; } void DeleteOper(EdgeNode *edge) { if(!edge) return;//注意当没有出度的情况 else if(edge->next) DeleteOper(edge->next); else delete edge; } void DeleteGraphList(GraphList &G) { for(int i=0;i<G.numVexes;i++) { DeleteOper(G.adjlist[i].fistedge); } } int main() { GraphList G; CreateGraphList(G); TopLogicalSort(G); DeleteGraphList(G); system("pause"); } int main() { cout<<"hello"<<endl; system("pause"); }
void TopLogicalSortIn(GraphList &G,int *etv,stack<int> &S_I) { cout<<"输出拓扑排序"<<endl; stack<int> S; int count=0; for(int i=0;i<G.numVexes;i++) { if(G.adjlist[i].in==0) S.push(i); } while(S.size()) { int a=S.top(); S.pop(); S_I.push(a);//事件入栈 count++; cout<<"v"<<a<<" "; EdgeNode *p=G.adjlist[a].fistedge; while(p) { if(!(--G.adjlist[p->adjvex].in))// S.push(p->adjvex); if((etv[a]+p->weight)>etv[p->adjvex]) etv[p->adjvex]=etv[a]+p->weight; p=p->next; } } if(count==G.numVexes) cout<<"TopLogicalSort ok"<<endl; else cout<<"TopLogicalSort error"<<endl; }
void CriticalPath(GraphList &G) { int *etv=new int[G.numVexes](); stack<int> S_I; TopLogicalSortIn(G,etv,S_I); cout<<endl; for(int i=0;i<G.numVexes;i++) cout<<etv[i]<<" "; //求ltv int *ltv=new int[G.numVexes]; for(int i=0;i<G.numVexes;i++)//初始化 { ltv[i]=etv[G.numVexes-1]; } while(S_I.size()) { int a=S_I.top(); S_I.pop(); EdgeNode *p; p=G.adjlist[a].fistedge; while(p) { int b=p->adjvex; int weight=p->weight; if(ltv[b]-weight < ltv[a]) ltv[a]=ltv[b]-weight; p=p->next; } } cout<<endl; for(int i=0;i<G.numVexes;i++) cout<<ltv[i]<<" "; cout<<"关键路径是"<<endl; for(int i=0;i<G.numVexes;i++)//直接可以从开始去遍历了,不用从后面开始遍历 { EdgeNode *p=G.adjlist[i].fistedge; while(p) { int b=p->adjvex; int weight=p->weight; if(etv[i]==(ltv[b]-weight)) cout<<"("<<i<<","<<b<<")"<<weight<<" "; p=p->next; } } delete etv; delete ltv; }