数据结构图论代码-描述篇

图论算法描述

    • 用于看文字描述后容易写出相对应的图论代码
    • dijkstra
    • floyd
    • DFS && BFS
    • Kruscal:
    • Prim:
    • topologicalsort

用于看文字描述后容易写出相对应的图论代码

这篇文章倾向于自用-代码是手撸源码,可以运行
图论的解析


**

dijkstra

**
1.设置初始点为true
2.初始点更新 「直接使用map中的行更新」
3.在剩下的顶点中选最小的顶点v
4.先设为true
5.使用顶点v更新「用dist数组中v+map中v行

#include 
#include
#include
#include
using namespace std;
const int N=100;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

/*
-------------------	Dijkstra  -----------------------------
从点A到其它所有点的最短路径 
*/

int	map[N][N];	//邻接矩阵表示图 
bool boo[N];	
int dis[N];
int a,b;
int c=0;
int foot[N];
int key1,key2,value;


void dijkstra(int key){
	foot[c++]=key;
	boo[key]=1;
	dis[key]=0;
	int tag=key;
	for(int i=0;i<a-1;++i){			//仅仅是枚举次数 
		//更新dis 
		for(int k1=0;k1<a;k1++){
			if(map[tag][k1]!=0 && map[tag][k1]!=INT_MAX && boo[k1]==0 ){	//当前k1需要更新 
				cout<<"dis[k1]:"<<dis[k1]<<endl;
				cout<<"dis[tag]:"<<dis[tag]<<endl; 
					//1. 当 dis=无穷  
					//2.	当有值   外来的比原来的小  
					if(dis[k1]==INT_MAX|| dis[tag]+map[tag][k1]<dis[k1]){
						dis[k1]=dis[tag]+map[tag][k1];
					}		
		 	}
		}
		//打印dis 
		cout<<"dis:"<<endl;
		for(int k=0;k<a;k++){
			cout<<dis[k]<<" ";
		}
		cout<<endl;
		
		//找最小的路径 
		cout<<"next:"<<endl;
		int next=INT_MAX;
		for(int j=0;j<a;j++){
			if(boo[j]!=1 && dis[j]!=0 && dis[j]<next){
				next=dis[j];
				tag=j;	
			}
		}
		cout<<"tag:"<<tag<<endl;
		boo[tag]=1;
		foot[c++]=tag;
	}
	
	//打印路径 
	cout<<endl;
	cout<<"foot:"<<endl;
	for(int i=0;i<a;i++){
		cout<<foot[i]<<"-"; 
	}
	
	//打印数值 
	cout<<"dis:"<<endl; 
	for(int i=0;i<a;i++){
		cout<<dis[i]<<"-"; 
	}
}

int main(int argc, char *argv[]) {
	
	int G[6][4];
	fill(G[0],G[0]+6*4,520);
	for(int i=0;i<6;i++){
		for(int j=0;j<4;j++){
			cout<<G[i][j]<<" ";
		}
		cout<<endl;
	}
	cout<<"请输入顶点数和边数:例如 5 6"<<endl; 
	cin>>a>>b;
	fill(map[0],map[0]+N*N,INT_MAX);
	fill(dis,dis+a,INT_MAX);
	for(int i=0;i<b;i++){
		cin>>key1>>key2>>value;
		map[key1][key2]=value;
		map[key2][key1]=value;
	}	
	
	
	for(int i=0;i<b;i++){
		for(int j=0;j<b;j++){
			if(i==j){
				map[i][j]=0;
				break;
			}
		}
	}
	cout<<"show map:"<<endl;
	for(int i=0;i<b;i++){
		for(int j=0;j<b;j++){
			cout<<map[i][j]<<" ";
		}
		cout<<endl;
	}
	dijkstra(0);	
	return 0;
}

**

floyd

**
1.用所有顶点更新图「二维数组」
2.「当前顶点v iv+vj 3.路径打印使用递归回溯

路径解析:
一开始二维数组所有所有设为-1
更新路径v时说明不是直接通路 是需要桥梁

只有时-1的时候才是直接通路相连的,输出u,v
不是-1则时中间点 递归 左边 递归右边

#include 
#include 
#include 
using namespace std;

const int N=100;

int map[N][N];

void init()
{
	for(int i=0; i<N; i++)
	{
		for(int j=0; j<N; j++)
		{
			map[i][j]=9999;
		}
	}
}

void floyd(int n)
{
	int i,j,k;
	for(int k=0;k<n;k++)
	{
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<n;j++)
			{
				if(i!=j)
					map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
			}
		}
	}
}

void PMap(int n)
{
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			cout<<map[i][j]<<" ";
		}
		cout<<endl;
	}
}
int main()
{
	int  n,v;
	init();
	cout<<"请输入顶点数和边数:"<<endl;
	cin>>n>>v;
	PMap(n);
	int key1,key2,cost;
	for(int i=0;i<v;i++)
	{
		cin>>key1>>key2>>cost;
		map[key1][key2]=map[key2][key1]=cost;
	}
	cout<<"input:"<<endl;
	PMap(n);
	floyd(n);
	cout<<"AA:"<<endl;
	PMap(n);
	return 0;	
}

DFS && BFS

遍历图 
都要直接遍历所有顶点函数:原因是避免非连通图,不相连的顶点没有遍历

BFS:
从一个顶点v开始
把v顶点的邻接点放入queue中
出队一个,打印一个 重复操作 
直到队列为空

#include 
#include 
#include 
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
/*
注意  遇到不连通的图 (类似森林的图)  要加一个BFStravel函数   因为会遍历不到另一个连通块
从这个函数开始     而不是BFS函数
void BFSTravel()
{
	
	for(所有顶点)
		 if(!vis)
			BFS()

}

*/



int map[5][5]={
	{0,1,0,1,0},
	{1,0,1,0,1},
	{0,1,0,0,0},
	{1,0,0,0,0},
	{0,1,0,0,0}
};
bool bmap[5];
queue<int> q;
int count=0;
int foot[5];
void bfs(){
	while(!q.empty()){
	int	key=q.front();
		q.pop();
		for(int i=0;i<5;i++){
			if(bmap[i]==false && map[key][i]==1){
				cout<<i+1<<endl;
				bmap[i]=true;
				foot[count++]=i;
				q.push(i);
				if(count==5){
					exit(0);
				}
			}
		}
	}
}

int main(int argc, char *argv[]) {
	int key=4; //数组从0开始  4实际是5 
	bmap[key]=true;
	foot[count++]=key;
	q.push(key);
	bfs(); 
	for(int i=0;i<5;i++){
		cout<<foot[i]<<"-";
	}
	cout<<endl;
	return 0;
}

DFS:
出口 count==n
key
找邻接点key i==1 「通路」
找到马上递归DFS i 找下一个邻接点

#include 
#include 
using namespace std;

/*
注意  遇到不连通的图 (类似森林的图)  要加一个DFStravel函数   因为会遍历不到另一个连通块
从这个函数开始     而不是DFS函数
void DFSTravel()
{
	
	for(所有顶点)
		 if(!vis)
			DFS()

}

*/


/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int map[5][5]={
	{0,1,0,1,0},
	{1,0,1,0,1},
	{0,1,0,0,0},
	{1,0,0,0,0},
	{0,1,0,0,0}
};
bool bmap[5];
int foot[5];
int count=0;
void  dfs(int key){
	foot[count++]=key;
	if(count==5){
		exit(0);
	}
	bmap[key]=true;
	for(int i=0;i<5;i++){
		if(bmap[i]==false && map[key][i]==1){
			cout<<i+1<<endl;
			dfs(i);
		}
	}
}

int main(int argc, char *argv[]) {
	dfs(2);  //从零开始 所以这个应该是实际的3 
	for(int i=0;i<5;i++){
		cout<<foot[i]<<"-";
	}
	cout<<endl;
	return 0;
}

Kruscal:

find函数
union函数
father数组
边集

如果没有顶点编号,给的是坐标,需要自动生成边集,则使用一个顶点 连n个顶点双循环
顶点编号使用i j
for( i=0;i for(j=i+1; j E[num].u=i; E[num].v=j;
E[num].cost=[计算];
num++;

num就是边的数量
sort 边集就可以使用kruscal算法了

#include 
#include
using namespace std;
const int N=1000;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

struct EDGE{
	int u,v,cost;
	void set(int a,int b,int w){
		u=a;
		v=b;
		cost=w;
	}
};

EDGE edge[N*N-1/2];

bool cmp(EDGE a, EDGE b){
	return a.cost<b.cost;
}

int father[N];

int find(int x){
	if(father[x]==-1){
		return x;
	}else{
		return father[x]=find(father[x]);
	}
} 

bool union1(int x ,int y){
	x=find(x);
	y=find(y);
	if(x==y){
		return false;
	}
	if(x>y){
		father[x]=y;
	}else{
		father[y]=x;
	}
	return true;
}

int main(int argc, char *argv[]) {
	int i;
	int v,w,cost;
	cout<<"请输入边数和顶点数:"<<endl;
	int m,t;
	cin>>m>>t;	
	cout<<"请输入边的信息 例如 1 2 10:"<<endl; 
	for(i=0;i<m;i++){
		cin>>v>>w>>cost;
		edge[i].set(v,w,cost);
	}
	sort(edge,edge+m,cmp);
	i=0;
	fill(father,father+m,-1);
	int sum=0,count=0;
	while(count!=t-1){
		if(union1(edge[i].u,edge[i].v)){
			cout<<edge[i].u<<"-"<<edge[i].v<<endl;
			sum+=edge[i].cost;
			count++;
		}
		i++;
	}
	cout<<"sum:"<<sum <<endl;
	return 0;
}

**

Prim:

**
1.先从一个顶点v开始 先设置为true
2.更新cost数组
3.进循环 直到count==n-1「所有顶点纳入图中」 
4.选最小 并设置true
5.更新cost数组

#include

using namespace std;

const int adjacent_matri_max=1000;

int vertex_num,edge_num;									//顶点数量 边数量
int	price=0;												//最小生成树代价 
int	adjacent_matri[adjacent_matri_max][adjacent_matri_max];	//邻接矩阵
bool visitied[adjacent_matri_max];							//定义标记数组 
int  l_cost[adjacent_matri_max];
int path[adjacent_matri_max];

//初始化邻接矩阵INT_MAX 
void init(){
	for(int i=0;i<vertex_num;i++){
		for(int j=0;j<vertex_num;j++){
			adjacent_matri[i][j]=INT_MAX;
		}
	}
	fill(visitied,visitied+vertex_num,false);
	fill(l_cost,l_cost+vertex_num,INT_MAX); 
	return ;
}

//Prim算法实现最小生成树 
void Prim(int key){
	//key  0-vertex 
	int k=0;
	path[k++]=key;
	do{
		visitied[key]=true;						//先把顶点设为访问 
		for(int i=0;i<vertex_num;i++){			//更新代价数组 
			l_cost[i]=min(l_cost[i],adjacent_matri[key][i]);	
		}
		int min_cost=INT_MAX;
		
		//找到之后下一轮才给路径 
		for(int i=0;i<vertex_num;i++){
			if(visitied[i]==false && l_cost[i]<min_cost){
				min_cost=l_cost[i];
				key=i;
			}
		}
		price+=min_cost;
		path[k]=key;
		cout<<k+1<<":"<<endl;
		cout<<"mint_cost:"<<min_cost<<endl;
		cout<<"price:"	<<price<<endl<<endl;
	}while(++k<vertex_num);
	
	return;
}

void PrintTree(int key){
	cout<<"最小生成树生成顺序:"<<endl;
//	cout<";
	int count=0;
	for(int i=0;i<vertex_num;i++){
//		if(key!=path[i]){
			cout<<path[i]<<" ";
//			if(count++!=vertex_num-2)
//				cout<<"->";
//		}
	}
}

int main(){
	int row,col;
	int key;
	int weight;
	cout<<"现在开始构造图:"<<endl;
	cout<<"请输入顶点数量:"<<endl;
	cin>>vertex_num;
	cout<<"请输入边的数量:"<<endl;
	cin>>edge_num;
	
	//初始化矩阵为INT最大值 	
	init();
	
	

	//生成图(邻接矩阵) 
	cout<<"请输入边(两个顶点表示)和边的权值:(共"<<edge_num<<"组(行))"<<endl;
	for(int i=0;i<edge_num;i++){
		cin>>row>>col;
		cin>>weight;
		adjacent_matri[row][col]=adjacent_matri[col][row]=weight;
	}
	
	for(int i=0;i<vertex_num;i++){
		for(int j=0;j<vertex_num;j++){
			cout<<adjacent_matri[i][j]<<" ";
		}
		cout<<endl;
	}
	
	cout<<"请输入起点顶点:"<<endl;	
	cin>>key;
	Prim(key);
	cout<<"最小生成树代价为:"<<price<<endl;		
 	PrintTree(key); 
	
	return 0;
} 

topologicalsort

:
1.把所有indegree为0的顶点入队
2.当队不为空
获取队头元素,并出队,记录。
使用队头元素找到相邻的边后 使该点入度-1
判断indegree为0入队
--------- 当count为n时 拓扑成功-----------否则 失败 因:成环

#include 
#include 
#include 
using namespace std;

const int N=100;

int map[N][N];
int  vis[N];

void topsort(int n)
{
	int in;
	//所有顶点依次去除 
	for(int i=0;i<n;i++)
	{
		//先找一个入度为0的节点;
		for(int j=0;j<n;j++)
		{
			for(int k=0;k<n;k++)
			{
				//纵坐标为入度 
				if(!vis[k])
				{
					vis[k]=-1;
					in=k;
					cout<<k<<endl;
					break;
				}
			}
		}
		//使用当前入度为0 的  in点 把所有以此点为入度的点  入度--
		for(int i=0;i<n;i++)
		{
			if(map[in][i]==1)
			{
				vis[i]--;	//入度--
				map[in][i]=0; //且不可达了 
			}
		} 
	}
}

int main()
{
	int  n,v;
	cout<<"请输入顶点数和边数:"<<endl;
	cin>>n>>v;
	int key1,key2;
	for(int i=0;i<v;i++)
	{
		cin>>key1>>key2;
		map[key1][key2]=1;	//key1->key2 
		vis[key2]++;	//key2入度+1	
	}
	topsort(n);

	return 0;	
}

求点赞
原创不易,点赞容易。
您的鼓励就是我的最大动力!!!。

本篇博客到此结束,谢谢大家观看。


你可能感兴趣的:(数据结构与算法,图论,算法,数据结构,java,经验分享)