数据结构与算法之----图
来源:互联网 发布:宜宾网络电视台 编辑:程序博客网 时间:2024/05/21 03:19
1、图的初始化
#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可能会出问题,所以记得打上()
2、图的遍历
2.1 深度优先遍历
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)函数部分,一定要做的是先打印。
2.2 广度优先遍历
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循环来解决所有递归的问题。
3、最小生成树
3.1 Prim算法
<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
4.1 克鲁斯卡尔算法(kruskal算法)
<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;}
4 5
请从小到大输入边
0 1 1
2 3 1
1 2 2
1 3 2
0 2 3
0 1 1
2 3 1
1 2 2
Press any key to continue
思想:
(1)顶点输入序号必须是要按照从小到大输入,小的在前面
(2)边必须按照由小到大输入,这样才能是最小生成树
(3)不断加入稍微长的,由小端标记可以达到的大端。 如果已经标记,那么大端标记为小端,这样就能够从联通的一点找到另外一点。
(4)若加入的边,不构成回路,那么记下这条边。
(5)其中find函数这种找法很不错。
5、最短路径算法
5.1 Dijkstra算法
<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为要到这个点其前一个点的下标
5.2 弗洛伊德算法(Floyd)
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];}
6、拓扑排序
#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");}
输出:
7、关键路径
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;elsecout<<"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]<<" ";//求ltvint *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;}
- 数据结构与算法之----图
- 数据结构与算法之图
- 数据结构与算法之十一 图
- 数据结构与算法之图计算
- 数据结构与算法学习笔记之--数据结构
- 数据结构与算法之----串
- 数据结构与算法之----树
- 数据结构与算法之队列
- 算法与数据结构之单链表
- 数据结构与算法之数组
- 算法与数据结构之排序
- 数据结构与算法之大纲
- 数据结构与算法之排序
- 数据结构与算法之排序
- 数据结构与算法之 字符串
- 数据结构与算法之排序
- 数据结构与算法之查找
- 数据结构与算法之排序
- 网络赚钱 签到就可以赚钱的网赚 持续更新
- Linux下rootkit-ddrk攻击获得root权限以及清除方法
- 10000 pcs free gift of chinese top grade brown film faced plywood
- 二叉树的先中后序遍历的递归和非递归实现
- MySQL数据库管理(二)单机环境下MySQL Cluster的安装
- 数据结构与算法之----图
- sublime 配置 vim模式 并修改 Esc快捷键
- C#网络编程系列文章(四)之TcpListener实现同步TCP服务器
- MultipleInputs实现reduce端连接
- 求1000以内的回文素数
- GHOST使用教程
- ubuntu编译环境搭建需要的内容
- 《我的互联网方法论》 周鸿祎 --- 用户至上, 体验为王, 免费模式, 颠覆创新
- 爱情发生器:36个问题+4分钟对视=告别单身